"""Backfill VAT summary entries.""" from datetime import datetime import logging import os.path import sys sys.path.append('') logging.basicConfig(level=logging.INFO) import boto3 # noqa: E402 from scripts.utils import get_env # noqa: E402 from scripts.utils import load_csv_file # noqa: E402 from scripts.utils import parse_boolean # noqa: E402 from scripts.utils import s3_full_path # noqa: E402 from moneyhub import models # noqa: E402 from moneyhub.connectors.ows_abacus_event import OwsAbacusEvent # noqa: E402 from moneyhub.constants.constants import SYSTEM_TIMEZONE # noqa: E402 from moneyhub.constants.constants import VatCategory # noqa: E402 RECORD_KEY_FORMAT = '{account_id}-{contract_id}-{vat_category}-{amount}' AWS_ACCOUNT_ID = '437795906767' if __name__ == '__main__': if len(sys.argv) == 1: logging.error('Missing filename CLI parameter') exit(1) environment = get_env('Environment', True) statement_period_id = int(get_env('STATEMENT_PERIOD_ID', True)) apply_to_ledger = get_env('APPLY_VAT_TO_LEDGER_FOR_KNR') == 'true' filename = sys.argv[1] data = load_csv_file(filename) if len(data) == 0: logging.error('No new entries to add') exit(1) date_now = datetime.now(SYSTEM_TIMEZONE) logging.info('Validating file data') formatted_entries = [] for idx, row in enumerate(data): # check vat amount payee currency base = float(row.get('base_amount_payee_currency', 0)) vat_rate = float(row.get('vat_rate', 0)) vat_amount = round(float(row.get('vat_amount_payee_currency', 0)), 2) expected_vat_amount = round(base * (vat_rate / 100), 2) # ensure the calculation is accurate (ignoring rounding difference) if vat_amount != expected_vat_amount and abs(vat_amount - expected_vat_amount) > 0.011: logging.error(f'Error: vat_amount_payee_currency on line {idx + 1} is incorrectly calculated. It should be {expected_vat_amount} if rounded to 2 decimal places, instead of {vat_amount}.') # noqa: E501 exit(1) formatted_entries.append( { 'account_id': int(row['account_id']), 'contract_id': int(row['contract_id']), 'statement_period_id': int(row['statement_period_id']), 'activity_statement_period_id': int(row['activity_statement_period_id']), 'vat_category': VatCategory[row['vat_category'].upper()], 'payee_currency_code': row['payee_currency_code'], 'vat_currency_code': row['vat_currency_code'], 'base_amount_payee_currency': row['base_amount_payee_currency'], 'vat_rate': row.get('vat_rate') or None, 'vat_amount_payee_currency': row.get('vat_amount_payee_currency') or None, 'vat_amount_vat_currency': row.get('vat_amount_vat_currency') or None, 'wht_amount_payee_currency': row.get('wht_amount_payee_currency') or None, 'wht_amount_vat_currency': row.get('wht_amount_vat_currency') or None, 'wht_rate': row.get('wht_rate') or None, 'net_amount_payee_currency': row['net_amount_payee_currency'], 'abacus_exempt_reason': row.get('abacus_exempt_reason') or None, 'description': row.get('description') or None, 'is_reporting_only': parse_boolean(row.get('is_reporting_only')), } ) mismatched_periods = 0 for row in formatted_entries: if row['statement_period_id'] != statement_period_id: logging.error(f"Mismatched statement period ID: {row['statement_period_id']}") mismatched_periods += 1 if mismatched_periods != 0: exit(1) existing_entries = models.LedgerVatSummary.get_by_statement_period(statement_period_id) existing_entries = [ RECORD_KEY_FORMAT.format( account_id=e.account_id, contract_id=e.contract_id, vat_category=e.vat_category, amount=float(e.base_amount_payee_currency)) for e in existing_entries ] repeated_entries = 0 for record in formatted_entries: record_key = RECORD_KEY_FORMAT.format( account_id=record['account_id'], contract_id=record['contract_id'], vat_category=record['vat_category'], amount=float(record['base_amount_payee_currency'])) if record_key in existing_entries: logging.error(f'Entry exists already: {record}') repeated_entries += 1 if repeated_entries != 0: exit(1) S3_BUCKET = f'{environment}-moneyhub-vat-summary' s3_client = boto3.client('s3') local_path = os.path.abspath(filename) file_extension = os.path.splitext(filename)[1] file_name = date_now.strftime('%Y%m%d%H%M%S') object_name = f'{statement_period_id}/{file_name}{file_extension}' full_s3_path = s3_full_path(S3_BUCKET, object_name) logging.info( f'Uploading document to S3: {full_s3_path}') s3_client.upload_file( Filename=local_path, Bucket=S3_BUCKET, Key=object_name, ExtraArgs={ 'ExpectedBucketOwner': AWS_ACCOUNT_ID } ) logging.info('Adding vat_summary_file entry') vat_summary_file = models.VatSummaryFile.create( statement_period_id=statement_period_id, file_location=full_s3_path, created_by='default_user_id' ) logging.info('Adding abacus event ingest') abacus_event_ingest = OwsAbacusEvent.create_abacus_event( event_name='ingest_vat_summary', target_id=vat_summary_file.vat_summary_file_id, target_type='vat_summary_file', statement_period_id=statement_period_id) logging.info('Ingesting data to the ledger_vat_summary') for entry in formatted_entries: models.LedgerVatSummary.create( statement_period_id=statement_period_id, abacus_event_id=abacus_event_ingest['abacus_event_id'], activity_statement_period_id=entry['activity_statement_period_id'], account_id=entry['account_id'], contract_id=entry['contract_id'], vat_category=entry['vat_category'], payee_currency_code=entry['payee_currency_code'], vat_currency_code=entry['vat_currency_code'], base_amount_payee_currency=entry['base_amount_payee_currency'], vat_rate=entry['vat_rate'], vat_amount_payee_currency=entry['vat_amount_payee_currency'], vat_amount_vat_currency=entry['vat_amount_vat_currency'], wht_rate=entry['wht_rate'], wht_amount_payee_currency=entry['wht_amount_payee_currency'], wht_amount_vat_currency=entry['wht_amount_vat_currency'], net_amount_payee_currency=entry['net_amount_payee_currency'], is_reporting_only=entry['is_reporting_only'], abacus_exempt_reason=entry['abacus_exempt_reason'], description=entry['description'], created_by='default_user_id', created_at=date_now, last_modified_by='default_user_id', last_modified=date_now, ) if apply_to_ledger: logging.info('Adding abacus event commit') abacus_event_commit = OwsAbacusEvent.create_abacus_event( event_name='commit_vat_summary', target_id=vat_summary_file.vat_summary_file_id, target_type='vat_summary_file', statement_period_id=statement_period_id)