File size: 8,530 Bytes
5707fbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import json
from datetime import datetime
import random
import pandas as pd
from typing import List, Dict
import os

class InvoiceGenerator:
    def __init__(self, data_dir: str = "data"):
        """Initialize the invoice generator with a data directory."""
        self.data_dir = data_dir
        os.makedirs(data_dir, exist_ok=True)
        self.ensure_contract_file()
    
    def ensure_contract_file(self) -> None:
        """Ensure contracts.json exists with initial data."""
        contracts_file = os.path.join(self.data_dir, "contracts.json")
        if not os.path.exists(contracts_file):
            initial_contracts = {
                "contracts": [
                    {
                        "contract_id": "CNT001",
                        "client": "TechCorp Solutions",
                        "start_date": "2024-01-01",
                        "end_date": "2024-12-31",
                        "terms": {
                            "base_rate": 100,
                            "volume_discounts": [
                                {"threshold": 1000, "discount": 0.10},
                                {"threshold": 5000, "discount": 0.15},
                                {"threshold": 10000, "discount": 0.20}
                            ],
                            "special_conditions": [
                                "Holiday surcharge: 15% on federal holidays",
                                "Rush order fee: Additional 25% for same-day delivery",
                                "Bulk order minimum: 500 units per order for volume pricing",
                                "Early payment discount: 2% if paid within 10 days",
                                "Multi-year commitment: 5% additional discount for 3+ year contract"
                            ]
                        }
                    },
                    {
                        "contract_id": "CNT002",
                        "client": "Global Manufacturing Inc",
                        "start_date": "2024-01-01",
                        "end_date": "2024-12-31",
                        "terms": {
                            "base_rate": 85,
                            "tiered_pricing": [
                                {"tier": "Standard", "rate": 1.0},
                                {"tier": "Premium", "rate": 1.25},
                                {"tier": "Enterprise", "rate": 1.5}
                            ],
                            "special_conditions": [
                                "Annual commitment discount: 5% off base rate",
                                "Multi-location discount: 3% per additional location",
                                "Payment terms: 2% discount for payment within 10 days",
                                "Volume guarantee: Minimum 1000 units per quarter",
                                "Service level agreement: 99.9% delivery accuracy required"
                            ]
                        }
                    }
                ]
            }
            with open(contracts_file, 'w') as f:
                json.dump(initial_contracts, f, indent=4)
    
    def load_contracts(self) -> List[Dict]:
        """Load contracts from JSON file."""
        contracts_file = os.path.join(self.data_dir, "contracts.json")
        try:
            with open(contracts_file, 'r') as f:
                contracts_data = json.load(f)
                return contracts_data['contracts']
        except Exception as e:
            raise Exception(f"Error loading contracts: {str(e)}")

    def calculate_correct_price(self, contract: Dict, quantity: int) -> float:
        """Calculate the correct price based on contract terms and quantity."""
        base_amount = contract["terms"]["base_rate"]
        price = base_amount * quantity
        
        # Apply volume discounts if applicable
        if "volume_discounts" in contract["terms"]:
            applicable_discount = 0
            for discount in sorted(
                contract["terms"]["volume_discounts"], 
                key=lambda x: x["threshold"], 
                reverse=True
            ):
                if quantity >= discount["threshold"]:
                    applicable_discount = discount["discount"]
                    break
            if applicable_discount > 0:
                price *= (1 - applicable_discount)
        
        # Apply tiered pricing if applicable
        if "tiered_pricing" in contract["terms"]:
            # Randomly select a tier for this invoice
            tier = random.choice(contract["terms"]["tiered_pricing"])
            price *= tier["rate"]
        
        return round(price, 2)

    def generate_invoices(self, contracts: List[Dict]) -> List[Dict]:
        """Generate synthetic invoices based on contract data."""
        invoices = []
        for contract in contracts:
            # Generate multiple invoices per contract
            for _ in range(random.randint(5, 10)):  # Random number of invoices per contract
                # Randomly decide if this invoice will have an error
                has_error = random.random() < 0.3  # 30% chance of error
                
                # Generate random quantity between contract minimums and maximums
                min_quantity = 500  # Minimum from special conditions
                max_quantity = 15000  # Arbitrary maximum
                quantity = random.randint(min_quantity, max_quantity)
                
                # Calculate correct price
                correct_price = self.calculate_correct_price(contract, quantity)
                
                # If we want an error, modify the price slightly
                charged_amount = correct_price
                if has_error:
                    error_factor = random.uniform(1.05, 1.15)  # 5-15% overcharge
                    charged_amount *= error_factor
                
                # Generate random date within contract period
                start_date = datetime.strptime(contract["start_date"], "%Y-%m-%d")
                end_date = datetime.strptime(contract["end_date"], "%Y-%m-%d")
                random_days = random.randint(0, (end_date - start_date).days)
                invoice_date = start_date + pd.Timedelta(days=random_days)
                
                invoice = {
                    "invoice_id": f"INV{random.randint(1000, 9999)}",
                    "contract_id": contract["contract_id"],
                    "date": invoice_date.strftime("%Y-%m-%d"),
                    "quantity": quantity,
                    "amount_charged": round(charged_amount, 2),
                    "correct_amount": round(correct_price, 2),
                    "has_error": has_error
                }
                invoices.append(invoice)
        
        return sorted(invoices, key=lambda x: x["date"])

    def save_invoices(self, invoices: List[Dict]) -> None:
        """Save generated invoices to JSON file."""
        invoices_file = os.path.join(self.data_dir, "invoices.json")
        with open(invoices_file, 'w') as f:
            json.dump({"invoices": invoices}, f, indent=2)

    def generate_and_save(self) -> None:
        """Generate and save invoices in one step."""
        contracts = self.load_contracts()
        invoices = self.generate_invoices(contracts)
        self.save_invoices(invoices)
        
    def load_or_generate_invoices(self) -> List[Dict]:
        """Load existing invoices or generate new ones if they don't exist."""
        invoices_file = os.path.join(self.data_dir, "invoices.json")
        try:
            if os.path.exists(invoices_file):
                with open(invoices_file, 'r') as f:
                    data = json.load(f)
                    return data.get('invoices', [])
            else:
                self.generate_and_save()
                with open(invoices_file, 'r') as f:
                    data = json.load(f)
                    return data.get('invoices', [])
        except Exception as e:
            print(f"Error loading invoices: {str(e)}")
            print("Generating new invoices...")
            self.generate_and_save()
            with open(invoices_file, 'r') as f:
                data = json.load(f)
                return data.get('invoices', [])

if __name__ == "__main__":
    # This allows running the generator directly to create/update the files
    generator = InvoiceGenerator()
    generator.generate_and_save()
    print("Successfully generated invoice and contract data!")