""" Logic for payments. Provides logic for calculating accounting payments """ from ows_accounting import config from ows_accounting import response from ows_accounting.constants import error from ows_accounting.constants import header from ows_accounting.logic import accounting_intervals from ows_accounting.models import currency as currency_model from ows_accounting.models import currency_exchange_rates from ows_accounting.models import payment from ows_accounting.models import period as period_model from ows_accounting.presentation import payments as payments_presentation def _get_payments_by_periods(vendor_id, intervals): """Get payments info by accounting periods from the database. Args: vendor_id (int): vendor_id. intervals (list): accounting intervals list Returns: list: List with formatted payments data by accounting periods """ periods = [] for interval in intervals: periods.extend(interval['periods']) return payment.get_vendor_payments(vendor_id, periods) def _format_payment(interval, currency): """Get properly formatted payment item for response. Args: interval (dict): Accounting interval data currency (dict): Currency data Returns: dict: Payment data """ return { 'min_accounting_period': interval['periods'][-1], 'max_accounting_period': interval['periods'][0], 'interval': { 'type': interval['type'], 'number': interval['number'], 'year': interval['year'] }, 'currency_id': currency['id'], 'currency_symbol': currency['symbol'], 'payment': 0, } def _get_sum_by_period_id(payments_data, period_id): """Get payments sum from payments data list by period id. Args: payments_data (list): Payments data list from art_relations database period_id (int): Accounting period id Returns: float: Payments sum """ return sum( (float(item.get('sum_check_amt', 0)) for item in payments_data if item['period_id'] == period_id)) def _convert_sum_for_period(sum, currency_id, period_id): """ Convert sum from default currency to another one using exchange course for period. Args: sum (float): Sum in default currency. currency_id (int): Currency id to convert into. period_id (int): Accounting period id Returns: response.Response: Response with converted sum or error """ exchange_response = currency_exchange_rates.get_currency_exchange_rate( period_id, currency_id) if not exchange_response: return exchange_response exchange_rate = exchange_response.message['exchange_rate'] return response.Response({ 'sum': sum * 1/float(exchange_rate) }) def _get_first_statement_period(account_id, account_type, intervals): """Filter revenue intervals based on first statement period. Args: account_id (int): account id. account_type (str): account type from GRASS. intervals (list): list of dictionaries with intervals details Returns: list: list of filtered dictionaries with intervals details. """ period = period_model.get_first_statement_period(account_id, account_type) first_statement_period_intervals = [] if not period: return intervals for interval in intervals: if period.message <= interval['periods'][0]: first_statement_period_intervals.append(interval) return first_statement_period_intervals def get_payments(account_type, account_id, recent_intervals): """Get account payments information. Args: account_type (str): account type from GRASS. account_id (int): account id. recent_intervals: number of intervals to get info Returns: response.Response: Payments info or error. """ if account_type == header.GRASS_ACCOUNT_TYPE_SUBACCOUNT: return response.create_error_response( code=error.ERROR_CODE_BAD_GRASS_REQUEST, message=error.ERROR_MESSAGE_INVALID_GRASS_ACCOUNT_TYPE) intervals_response = accounting_intervals.get_intervals_from_contracts( account_type, account_id, recent_intervals) if not intervals_response: return intervals_response intervals = intervals_response.message payments_response = _get_payments_by_periods(account_id, intervals) if not payments_response: return payments_response payments_data = payments_presentation.payments( payments_response.message['items']) result = [] intervals = _get_first_statement_period( account_id, account_type, intervals) for interval in intervals: currency_response = currency_model.get_currency_by_id( interval['currency_id']) if not currency_response: return currency_response currency_info = currency_response.message payment_record = _format_payment(interval, currency_info) for period_id in interval['periods']: payments_sum = _get_sum_by_period_id(payments_data, period_id) if (payments_sum > 0 and currency_info['code'] != config.DEFAULT_CURRENCY_CODE): conversion = _convert_sum_for_period( payments_sum, currency_info['id'], period_id) if not conversion: return conversion payments_sum = float(conversion.message['sum']) payment_record['payment'] += payments_sum result.append(payment_record) return response.Response(result)