Sadržaj
Technical Specification: Invoice-to-Quota Synchronizationn
This document outlines the logic for the automated Invoice-to-Quota synchronization task. The system ensures that every paid service is translated into a usable member entitlement while respecting complex “Package” (BOM) structures and recurring billing cycles.
1. System Objective
The goal is to automate the creation of member “quotas” (entry entitlements) based on successful invoice generation. For every invoice issued to a member for a specific service, the system must generate a corresponding quota record that defines what they can do, how many times, and for how long.
2. The Core Data Entities
The logic draws from five distinct functional areas of your database:
- Transactions (dok, dok_items): The source of truth for what was purchased and when.
- Membership & Services (sif_clan, sif_art): The master files for who the members are and what services/packages exist.
- Recurring Logic (osn_zad): The “engine” that defines the billing frequency and the duration of the service (Days vs. Months).
- Recipes/Packages (osn_sastavnice, osn_sastavke): The breakdown logic for “bundled” services (e.g., a “VIP Package” that consists of 10 Gym entries and 2 Saunas).
- Entitlements (gym_quota, gym_quotad): The destination tables that control the member’s actual access rights.
3. Procedural Logic & Filtering
To ensure data integrity and business accuracy, the extraction process follows a strict hierarchy of filters:
A. Authorization Gatekeepers
Data is only extracted if:
- Company Level: The company (sif_pod) is active and has purchased the specific Module 50.
- Department Level: The department (sif_oj) is active.
- Config Level: The specific setting OJ_CLAN = 'F' exists in osn_setoj for that department.
B. The "Package Explosion" (BOM Logic)
The system distinguishes between standalone services and packages using the sif_art.ru flag:
- Simple Service (ru != 'Y'): The item is moved directly to the quota.
- Package Service (ru = 'Y'): The system “explodes” the item into its individual components via the osn_sastavke table. The final quota quantity is calculated as:
- Total_Qty=Invoice_Qty×Recipe_Ingredient_Qty
C. Temporal Logic (Date Calculations)
Instead of using a fixed duration, the system calculates the expiry date (edate) dynamically based on the subscription master (osn_zad):
- Daily Frequency (dm = 'D'): edate = sdate + frek
- Monthly Frequency (dm = 'M'): edate = sdate + (frek * months)
- Cycle Alignment: The sdate is anchored to the membership start date (poc), moving forward in cycles to align with the current invoice period.
4. Integration Strategy (Python Task)
The task is designed to be idempotent, meaning it can run multiple times without creating duplicate records.
- Identification: A LEFT JOIN between dok and gym_quota identifies invoices that do not yet have an assigned quota.
- Transformation: The SQL handles the complex joining of configuration settings and package recipes in a single pass.
- Insertion: The Python script performs a two-stage transactional insert:
- Stage 1: Insert into gym_quota (The Header).
- Stage 2: Use the RETURNING id from Stage 1 to populate gym_quotad (The Details) with the exploded list of services.
5. Summary of Key Mappings
| Logic | Source Table | Target Field |
|---|---|---|
| Whom | dok.clan | gym_quota.member |
| Why | dok.id | gym_quota.dok |
| When (Start) | osn_zad.poc (Cycle adjusted) | gym_quota.sdate |
| When (End) | osn_zad (dm/frek calculation) | gym_quota.edate |
| What (Items) | sif_art (exploded via osn_sastavke) | gym_quotad.art |