fixed cob report
This commit is contained in:
parent
c22dabf943
commit
d61275ca85
|
|
@ -25,14 +25,6 @@ frappe.query_reports["Customer Outstanding Balance"] = {
|
||||||
"default": frappe.datetime.get_today(),
|
"default": frappe.datetime.get_today(),
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "customer",
|
|
||||||
"label": __("Customer"),
|
|
||||||
"fieldtype": "MultiSelectList",
|
|
||||||
"get_data": function (txt) {
|
|
||||||
return frappe.db.get_link_options("Customer", txt);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "customer_group",
|
"fieldname": "customer_group",
|
||||||
"label": __("Customer Group"),
|
"label": __("Customer Group"),
|
||||||
|
|
@ -44,41 +36,80 @@ frappe.query_reports["Customer Outstanding Balance"] = {
|
||||||
"formatter": function (value, row, column, data, default_formatter) {
|
"formatter": function (value, row, column, data, default_formatter) {
|
||||||
value = default_formatter(value, row, column, data);
|
value = default_formatter(value, row, column, data);
|
||||||
|
|
||||||
// Highlight opening balance in blue
|
if (!data) return value;
|
||||||
if (column.fieldname == "opening_balance" && data && data.opening_balance > 0) {
|
|
||||||
|
// Original columns highlighting
|
||||||
|
if (column.fieldname == "opening_balance" && data.opening_balance > 0) {
|
||||||
value = "<span style='color: #1f77b4; font-weight: bold;'>" + value + "</span>";
|
value = "<span style='color: #1f77b4; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight payments in green
|
if (column.fieldname == "payments" && data.payments > 0) {
|
||||||
if (column.fieldname == "payments" && data && data.payments > 0) {
|
|
||||||
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight new invoices in orange
|
if (column.fieldname == "new_invoices" && data.new_invoices > 0) {
|
||||||
if (column.fieldname == "new_invoices" && data && data.new_invoices > 0) {
|
|
||||||
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight closing balance in dark red
|
if (column.fieldname == "closing_balance" && data.closing_balance > 0) {
|
||||||
if (column.fieldname == "closing_balance" && data && data.closing_balance > 0) {
|
|
||||||
value = "<span style='color: #d62728; font-weight: bold;'>" + value + "</span>";
|
value = "<span style='color: #d62728; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight VAT allocation columns
|
// Tax template columns highlighting
|
||||||
if (column.fieldname == "edv_daxil_18" && data && data.edv_daxil_18 > 0) {
|
// ƏDV 18% - Purple tones
|
||||||
value = "<span style='color: #17a2b8; font-weight: bold;'>" + value + "</span>";
|
if (column.fieldname == "edv_18_opening" && data.edv_18_opening > 0) {
|
||||||
|
value = "<span style='color: #9467bd; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_18_plus" && data.edv_18_plus > 0) {
|
||||||
|
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_18_minus" && data.edv_18_minus > 0) {
|
||||||
|
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_18_closing" && data.edv_18_closing > 0) {
|
||||||
|
value = "<span style='color: #8c564b; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column.fieldname == "edv_azadolma" && data && data.edv_azadolma > 0) {
|
// ƏDV daxil 18% - Blue-green tones
|
||||||
value = "<span style='color: #28a745; font-weight: bold;'>" + value + "</span>";
|
if (column.fieldname == "edv_daxil_18_opening" && data.edv_daxil_18_opening > 0) {
|
||||||
|
value = "<span style='color: #17becf; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_daxil_18_plus" && data.edv_daxil_18_plus > 0) {
|
||||||
|
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_daxil_18_minus" && data.edv_daxil_18_minus > 0) {
|
||||||
|
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_daxil_18_closing" && data.edv_daxil_18_closing > 0) {
|
||||||
|
value = "<span style='color: #1f77b4; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column.fieldname == "edv_0" && data && data.edv_0 > 0) {
|
// ƏDV 0% - Green tones
|
||||||
value = "<span style='color: #ffc107; font-weight: bold;'>" + value + "</span>";
|
if (column.fieldname == "edv_0_opening" && data.edv_0_opening > 0) {
|
||||||
|
value = "<span style='color: #bcbd22; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_0_plus" && data.edv_0_plus > 0) {
|
||||||
|
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_0_minus" && data.edv_0_minus > 0) {
|
||||||
|
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_0_closing" && data.edv_0_closing > 0) {
|
||||||
|
value = "<span style='color: #7f7f7f; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column.fieldname == "edv_18" && data && data.edv_18 > 0) {
|
// ƏDV-dən azadolma - Pink-red tones
|
||||||
value = "<span style='color: #dc3545; font-weight: bold;'>" + value + "</span>";
|
if (column.fieldname == "edv_azadolma_opening" && data.edv_azadolma_opening > 0) {
|
||||||
|
value = "<span style='color: #e377c2; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_azadolma_plus" && data.edv_azadolma_plus > 0) {
|
||||||
|
value = "<span style='color: #ff7f0e; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_azadolma_minus" && data.edv_azadolma_minus > 0) {
|
||||||
|
value = "<span style='color: #2ca02c; font-weight: bold;'>" + value + "</span>";
|
||||||
|
}
|
||||||
|
if (column.fieldname == "edv_azadolma_closing" && data.edv_azadolma_closing > 0) {
|
||||||
|
value = "<span style='color: #d62728; font-weight: bold;'>" + value + "</span>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
"""Main function for report execution"""
|
"""Main function for report execution"""
|
||||||
|
|
@ -13,8 +14,8 @@ def execute(filters=None):
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
def get_columns():
|
def get_columns():
|
||||||
"""Get report columns definition"""
|
"""Get report columns definition with 16 new columns for tax templates"""
|
||||||
return [
|
columns = [
|
||||||
{
|
{
|
||||||
"label": _("Customer"),
|
"label": _("Customer"),
|
||||||
"fieldname": "customer",
|
"fieldname": "customer",
|
||||||
|
|
@ -51,38 +52,64 @@ def get_columns():
|
||||||
"fieldname": "closing_balance",
|
"fieldname": "closing_balance",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"width": 140
|
"width": 140
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": _("ƏDV daxil 18%"),
|
|
||||||
"fieldname": "edv_daxil_18",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"width": 140
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": _("ƏDV-dən azadolma"),
|
|
||||||
"fieldname": "edv_azadolma",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"width": 140
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": _("ƏDV 0%"),
|
|
||||||
"fieldname": "edv_0",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"width": 140
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": _("ƏDV 18%"),
|
|
||||||
"fieldname": "edv_18",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"width": 140
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Add 16 columns for 4 tax templates
|
||||||
|
tax_templates = [
|
||||||
|
{"name": "ƏDV 18%", "prefix": "edv_18"},
|
||||||
|
{"name": "ƏDV daxil 18%", "prefix": "edv_daxil_18"},
|
||||||
|
{"name": "ƏDV 0%", "prefix": "edv_0"},
|
||||||
|
{"name": "ƏDV-dən azadolma", "prefix": "edv_azadolma"}
|
||||||
|
]
|
||||||
|
|
||||||
|
for template in tax_templates:
|
||||||
|
columns.extend([
|
||||||
|
{
|
||||||
|
"label": _(f"{template['name']} Opening"),
|
||||||
|
"fieldname": f"{template['prefix']}_opening",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 130
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _(f"{template['name']} +"),
|
||||||
|
"fieldname": f"{template['prefix']}_plus",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 130
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _(f"{template['name']} -"),
|
||||||
|
"fieldname": f"{template['prefix']}_minus",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 130
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _(f"{template['name']} Closing"),
|
||||||
|
"fieldname": f"{template['prefix']}_closing",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"width": 130
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
def get_data(filters):
|
def get_data(filters):
|
||||||
"""Get report data"""
|
"""Get report data from VAT Allocation documents"""
|
||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
|
|
||||||
# Get opening balance (before from_date)
|
# Get current period VAT Allocation
|
||||||
|
from_date = datetime.strptime(filters.get('from_date'), '%Y-%m-%d')
|
||||||
|
to_date = datetime.strptime(filters.get('to_date'), '%Y-%m-%d')
|
||||||
|
|
||||||
|
current_year = from_date.year
|
||||||
|
current_month = from_date.strftime('%B') # Full month name
|
||||||
|
|
||||||
|
# Get previous month for opening balance
|
||||||
|
previous_date = from_date - relativedelta(months=1)
|
||||||
|
previous_year = previous_date.year
|
||||||
|
previous_month = previous_date.strftime('%B')
|
||||||
|
|
||||||
|
# Get opening balance (before from_date) - original ledger-based calculation
|
||||||
opening_balance_data = frappe.db.sql(f"""
|
opening_balance_data = frappe.db.sql(f"""
|
||||||
SELECT
|
SELECT
|
||||||
ple.party as customer,
|
ple.party as customer,
|
||||||
|
|
@ -103,7 +130,7 @@ def get_data(filters):
|
||||||
ABS(opening_balance) >= 0.01
|
ABS(opening_balance) >= 0.01
|
||||||
""", filters, as_dict=1)
|
""", filters, as_dict=1)
|
||||||
|
|
||||||
# Get movements during the period
|
# Get movements during the period - original ledger-based calculation
|
||||||
period_data = frappe.db.sql(f"""
|
period_data = frappe.db.sql(f"""
|
||||||
SELECT
|
SELECT
|
||||||
ple.party as customer,
|
ple.party as customer,
|
||||||
|
|
@ -124,7 +151,7 @@ def get_data(filters):
|
||||||
ple.party
|
ple.party
|
||||||
""", filters, as_dict=1)
|
""", filters, as_dict=1)
|
||||||
|
|
||||||
# Get closing balance (up to to_date)
|
# Get closing balance (up to to_date) - original ledger-based calculation
|
||||||
closing_balance_data = frappe.db.sql(f"""
|
closing_balance_data = frappe.db.sql(f"""
|
||||||
SELECT
|
SELECT
|
||||||
ple.party as customer,
|
ple.party as customer,
|
||||||
|
|
@ -145,11 +172,16 @@ def get_data(filters):
|
||||||
ABS(closing_balance) >= 0.01
|
ABS(closing_balance) >= 0.01
|
||||||
""", filters, as_dict=1)
|
""", filters, as_dict=1)
|
||||||
|
|
||||||
# Get VAT allocation data
|
# Get VAT Allocation data for tax templates
|
||||||
vat_data = get_vat_allocation_data(filters)
|
vat_current = get_vat_allocation_data(current_year, current_month, filters.get('company'))
|
||||||
|
vat_previous = get_vat_allocation_data(previous_year, previous_month, filters.get('company'))
|
||||||
|
|
||||||
|
# Get Sales Invoice data directly for current month (for "+" column)
|
||||||
|
si_current = get_sales_invoice_data(current_year, current_month, filters.get('company'))
|
||||||
|
|
||||||
# Combine all data
|
# Combine all data
|
||||||
result = combine_data(opening_balance_data, period_data, closing_balance_data, vat_data)
|
result = combine_data(opening_balance_data, period_data, closing_balance_data,
|
||||||
|
vat_current, vat_previous, si_current)
|
||||||
|
|
||||||
# Get customer names and other details
|
# Get customer names and other details
|
||||||
add_customer_details(result)
|
add_customer_details(result)
|
||||||
|
|
@ -160,77 +192,114 @@ def get_conditions(filters):
|
||||||
"""Build WHERE conditions based on filters"""
|
"""Build WHERE conditions based on filters"""
|
||||||
conditions = ""
|
conditions = ""
|
||||||
|
|
||||||
if filters.get("customer"):
|
|
||||||
customer_list = "', '".join(filters.get("customer"))
|
|
||||||
conditions += f" AND ple.party IN ('{customer_list}')"
|
|
||||||
|
|
||||||
if filters.get("customer_group"):
|
if filters.get("customer_group"):
|
||||||
conditions += " AND ple.party IN (SELECT name FROM `tabCustomer` WHERE customer_group = %(customer_group)s)"
|
conditions += " AND ple.party IN (SELECT name FROM `tabCustomer` WHERE customer_group = %(customer_group)s)"
|
||||||
|
|
||||||
return conditions
|
return conditions
|
||||||
|
|
||||||
def get_vat_allocation_data(filters):
|
def get_vat_allocation_data(year, month, company):
|
||||||
"""Get VAT allocation data for customers in the period"""
|
"""
|
||||||
if not filters.get("from_date") or not filters.get("to_date"):
|
Get VAT allocation data for specified year and month
|
||||||
return []
|
Returns dict with customer -> tax_template -> {unallocated, allocated}
|
||||||
|
"""
|
||||||
|
# Find VAT Allocation document
|
||||||
|
vat_name = f"VAT-{year}-{month}"
|
||||||
|
|
||||||
# Determine year and month from the date range
|
if not frappe.db.exists("VAT allocation", vat_name):
|
||||||
from_date = datetime.strptime(str(filters.get("from_date")), "%Y-%m-%d")
|
return {}
|
||||||
to_date = datetime.strptime(str(filters.get("to_date")), "%Y-%m-%d")
|
|
||||||
|
|
||||||
# Get month name mapping
|
# Get sales invoice table data from VAT allocation
|
||||||
month_names = [
|
sales_data = frappe.db.sql("""
|
||||||
"January", "February", "March", "April", "May", "June",
|
|
||||||
"July", "August", "September", "October", "November", "December"
|
|
||||||
]
|
|
||||||
|
|
||||||
# Use the to_date for determining the period
|
|
||||||
year = to_date.year
|
|
||||||
month = month_names[to_date.month - 1]
|
|
||||||
|
|
||||||
# Query VAT allocation sales invoice data from submitted documents
|
|
||||||
vat_query = """
|
|
||||||
SELECT
|
SELECT
|
||||||
vasi.customer,
|
customer,
|
||||||
vasi.item_tax_template,
|
item_tax_template,
|
||||||
SUM(vasi.allocated_amount) as allocated_amount
|
SUM(unallocated_amount) as total_unallocated,
|
||||||
|
SUM(allocated_amount) as total_allocated
|
||||||
FROM
|
FROM
|
||||||
`tabVAT allocation sales invoice` vasi
|
`tabVAT allocation sales invoice`
|
||||||
INNER JOIN
|
|
||||||
`tabVAT allocation` va ON va.name = vasi.parent
|
|
||||||
WHERE
|
WHERE
|
||||||
va.docstatus = 1
|
parent = %(vat_name)s
|
||||||
AND va.year = %(year)s
|
|
||||||
AND va.month = %(month)s
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Add customer filter if specified
|
|
||||||
customer_condition = ""
|
|
||||||
if filters.get("customer"):
|
|
||||||
customer_list = "', '".join(filters.get("customer"))
|
|
||||||
customer_condition = f" AND vasi.customer IN ('{customer_list}')"
|
|
||||||
|
|
||||||
if filters.get("customer_group"):
|
|
||||||
customer_condition += " AND vasi.customer IN (SELECT name FROM `tabCustomer` WHERE customer_group = %(customer_group)s)"
|
|
||||||
|
|
||||||
vat_query += customer_condition + """
|
|
||||||
GROUP BY
|
GROUP BY
|
||||||
vasi.customer, vasi.item_tax_template
|
customer, item_tax_template
|
||||||
|
""", {"vat_name": vat_name}, as_dict=1)
|
||||||
|
|
||||||
|
# Organize data by customer and tax template
|
||||||
|
result = {}
|
||||||
|
for row in sales_data:
|
||||||
|
customer = row['customer']
|
||||||
|
template = row['item_tax_template']
|
||||||
|
|
||||||
|
if customer not in result:
|
||||||
|
result[customer] = {}
|
||||||
|
|
||||||
|
result[customer][template] = {
|
||||||
|
'unallocated': row['total_unallocated'] or 0.0,
|
||||||
|
'allocated': row['total_allocated'] or 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_sales_invoice_data(year, month, company):
|
||||||
"""
|
"""
|
||||||
|
Get Sales Invoice data directly for the specified month
|
||||||
|
Returns dict with customer -> tax_template -> amount
|
||||||
|
"""
|
||||||
|
# Convert month name to number
|
||||||
|
months = {
|
||||||
|
"January": 1, "February": 2, "March": 3, "April": 4,
|
||||||
|
"May": 5, "June": 6, "July": 7, "August": 8,
|
||||||
|
"September": 9, "October": 10, "November": 11, "December": 12
|
||||||
|
}
|
||||||
|
|
||||||
vat_data = frappe.db.sql(vat_query, {
|
month_number = months.get(month)
|
||||||
"year": year,
|
if not month_number:
|
||||||
"month": month,
|
return {}
|
||||||
"customer_group": filters.get("customer_group")
|
|
||||||
}, as_dict=1)
|
|
||||||
|
|
||||||
return vat_data
|
# Get Sales Invoice items directly
|
||||||
|
invoice_data = frappe.db.sql("""
|
||||||
|
SELECT
|
||||||
|
si.customer,
|
||||||
|
sii.item_tax_template,
|
||||||
|
SUM(sii.amount) as total_amount
|
||||||
|
FROM
|
||||||
|
`tabSales Invoice` si
|
||||||
|
INNER JOIN
|
||||||
|
`tabSales Invoice Item` sii ON si.name = sii.parent
|
||||||
|
WHERE
|
||||||
|
si.docstatus = 1
|
||||||
|
AND YEAR(si.posting_date) = %(year)s
|
||||||
|
AND MONTH(si.posting_date) = %(month)s
|
||||||
|
AND si.company = %(company)s
|
||||||
|
GROUP BY
|
||||||
|
si.customer, sii.item_tax_template
|
||||||
|
""", {"year": year, "month": month_number, "company": company}, as_dict=1)
|
||||||
|
|
||||||
def combine_data(opening_data, period_data, closing_data, vat_data):
|
# Organize data by customer and tax template
|
||||||
|
result = {}
|
||||||
|
for row in invoice_data:
|
||||||
|
customer = row['customer']
|
||||||
|
template = row['item_tax_template']
|
||||||
|
|
||||||
|
if customer not in result:
|
||||||
|
result[customer] = {}
|
||||||
|
|
||||||
|
result[customer][template] = row['total_amount'] or 0.0
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def combine_data(opening_data, period_data, closing_data, vat_current, vat_previous, si_current):
|
||||||
"""Combine all datasets into final result"""
|
"""Combine all datasets into final result"""
|
||||||
result_dict = {}
|
result_dict = {}
|
||||||
|
|
||||||
# Add opening balances
|
# Tax template mapping
|
||||||
|
template_map = {
|
||||||
|
"ƏDV 18%": "edv_18",
|
||||||
|
"ƏDV daxil 18%": "edv_daxil_18",
|
||||||
|
"ƏDV 0%": "edv_0",
|
||||||
|
"ƏDV-dən azadolma": "edv_azadolma"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add opening balances (original logic)
|
||||||
for row in opening_data:
|
for row in opening_data:
|
||||||
customer = row['customer']
|
customer = row['customer']
|
||||||
result_dict[customer] = {
|
result_dict[customer] = {
|
||||||
|
|
@ -238,14 +307,16 @@ def combine_data(opening_data, period_data, closing_data, vat_data):
|
||||||
'opening_balance': row['opening_balance'] or 0.0,
|
'opening_balance': row['opening_balance'] or 0.0,
|
||||||
'payments': 0.0,
|
'payments': 0.0,
|
||||||
'new_invoices': 0.0,
|
'new_invoices': 0.0,
|
||||||
'closing_balance': 0.0,
|
'closing_balance': 0.0
|
||||||
'edv_daxil_18': 0.0,
|
|
||||||
'edv_azadolma': 0.0,
|
|
||||||
'edv_0': 0.0,
|
|
||||||
'edv_18': 0.0
|
|
||||||
}
|
}
|
||||||
|
# Initialize tax template fields
|
||||||
|
for prefix in template_map.values():
|
||||||
|
result_dict[customer][f'{prefix}_opening'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_plus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_minus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_closing'] = 0.0
|
||||||
|
|
||||||
# Add period movements
|
# Add period movements (original logic)
|
||||||
for row in period_data:
|
for row in period_data:
|
||||||
customer = row['customer']
|
customer = row['customer']
|
||||||
if customer not in result_dict:
|
if customer not in result_dict:
|
||||||
|
|
@ -254,17 +325,19 @@ def combine_data(opening_data, period_data, closing_data, vat_data):
|
||||||
'opening_balance': 0.0,
|
'opening_balance': 0.0,
|
||||||
'payments': 0.0,
|
'payments': 0.0,
|
||||||
'new_invoices': 0.0,
|
'new_invoices': 0.0,
|
||||||
'closing_balance': 0.0,
|
'closing_balance': 0.0
|
||||||
'edv_daxil_18': 0.0,
|
|
||||||
'edv_azadolma': 0.0,
|
|
||||||
'edv_0': 0.0,
|
|
||||||
'edv_18': 0.0
|
|
||||||
}
|
}
|
||||||
|
# Initialize tax template fields
|
||||||
|
for prefix in template_map.values():
|
||||||
|
result_dict[customer][f'{prefix}_opening'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_plus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_minus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_closing'] = 0.0
|
||||||
|
|
||||||
result_dict[customer]['payments'] = row['payments'] or 0.0
|
result_dict[customer]['payments'] = row['payments'] or 0.0
|
||||||
result_dict[customer]['new_invoices'] = row['new_invoices'] or 0.0
|
result_dict[customer]['new_invoices'] = row['new_invoices'] or 0.0
|
||||||
|
|
||||||
# Add closing balances
|
# Add closing balances (original logic)
|
||||||
for row in closing_data:
|
for row in closing_data:
|
||||||
customer = row['customer']
|
customer = row['customer']
|
||||||
if customer not in result_dict:
|
if customer not in result_dict:
|
||||||
|
|
@ -273,56 +346,87 @@ def combine_data(opening_data, period_data, closing_data, vat_data):
|
||||||
'opening_balance': 0.0,
|
'opening_balance': 0.0,
|
||||||
'payments': 0.0,
|
'payments': 0.0,
|
||||||
'new_invoices': 0.0,
|
'new_invoices': 0.0,
|
||||||
'closing_balance': 0.0,
|
'closing_balance': 0.0
|
||||||
'edv_daxil_18': 0.0,
|
|
||||||
'edv_azadolma': 0.0,
|
|
||||||
'edv_0': 0.0,
|
|
||||||
'edv_18': 0.0
|
|
||||||
}
|
}
|
||||||
|
# Initialize tax template fields
|
||||||
|
for prefix in template_map.values():
|
||||||
|
result_dict[customer][f'{prefix}_opening'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_plus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_minus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_closing'] = 0.0
|
||||||
|
|
||||||
result_dict[customer]['closing_balance'] = row['closing_balance'] or 0.0
|
result_dict[customer]['closing_balance'] = row['closing_balance'] or 0.0
|
||||||
|
|
||||||
# Add VAT allocation data
|
# Get all customers from all sources
|
||||||
for row in vat_data:
|
all_customers = set(result_dict.keys())
|
||||||
customer = row['customer']
|
all_customers.update(vat_current.keys())
|
||||||
|
all_customers.update(vat_previous.keys())
|
||||||
|
all_customers.update(si_current.keys())
|
||||||
|
|
||||||
|
# Add VAT allocation data for tax templates
|
||||||
|
for customer in all_customers:
|
||||||
|
# Ensure customer exists in result_dict
|
||||||
if customer not in result_dict:
|
if customer not in result_dict:
|
||||||
result_dict[customer] = {
|
result_dict[customer] = {
|
||||||
'customer': customer,
|
'customer': customer,
|
||||||
'opening_balance': 0.0,
|
'opening_balance': 0.0,
|
||||||
'payments': 0.0,
|
'payments': 0.0,
|
||||||
'new_invoices': 0.0,
|
'new_invoices': 0.0,
|
||||||
'closing_balance': 0.0,
|
'closing_balance': 0.0
|
||||||
'edv_daxil_18': 0.0,
|
|
||||||
'edv_azadolma': 0.0,
|
|
||||||
'edv_0': 0.0,
|
|
||||||
'edv_18': 0.0
|
|
||||||
}
|
}
|
||||||
|
# Initialize tax template fields
|
||||||
|
for prefix in template_map.values():
|
||||||
|
result_dict[customer][f'{prefix}_opening'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_plus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_minus'] = 0.0
|
||||||
|
result_dict[customer][f'{prefix}_closing'] = 0.0
|
||||||
|
|
||||||
# Map item tax template to field names
|
# Get data for this customer
|
||||||
template = row['item_tax_template']
|
customer_current = vat_current.get(customer, {})
|
||||||
allocated = row['allocated_amount'] or 0.0
|
customer_previous = vat_previous.get(customer, {})
|
||||||
|
customer_si = si_current.get(customer, {})
|
||||||
|
|
||||||
if 'daxil 18' in template or 'daxil18' in template.lower().replace(' ', ''):
|
for template_name, prefix in template_map.items():
|
||||||
result_dict[customer]['edv_daxil_18'] += allocated
|
# Previous month data (for opening balance)
|
||||||
elif 'azadolma' in template.lower():
|
prev_data = customer_previous.get(template_name, {'unallocated': 0.0, 'allocated': 0.0})
|
||||||
result_dict[customer]['edv_azadolma'] += allocated
|
opening = prev_data['unallocated'] # Closing of previous month = unallocated amount
|
||||||
elif '0%' in template or 'edv 0' in template.lower():
|
|
||||||
result_dict[customer]['edv_0'] += allocated
|
# Current month data
|
||||||
elif '18%' in template or 'edv 18' in template.lower():
|
curr_data = customer_current.get(template_name, {'unallocated': 0.0, 'allocated': 0.0})
|
||||||
result_dict[customer]['edv_18'] += allocated
|
minus = curr_data['allocated'] # Payments (allocated amount)
|
||||||
|
|
||||||
|
# Sales Invoice data for "+" (new invoices)
|
||||||
|
plus = customer_si.get(template_name, 0.0)
|
||||||
|
|
||||||
|
# Calculate closing
|
||||||
|
closing = opening + plus - minus
|
||||||
|
|
||||||
|
result_dict[customer][f'{prefix}_opening'] = opening
|
||||||
|
result_dict[customer][f'{prefix}_plus'] = plus
|
||||||
|
result_dict[customer][f'{prefix}_minus'] = minus
|
||||||
|
result_dict[customer][f'{prefix}_closing'] = closing
|
||||||
|
|
||||||
# Convert to list and filter out zero balances
|
# Convert to list and filter out zero balances
|
||||||
result = []
|
result = []
|
||||||
for customer, data in result_dict.items():
|
for customer, data in result_dict.items():
|
||||||
# Only include if there's some activity or outstanding balance
|
# Check if there's any activity
|
||||||
if (abs(data['opening_balance']) >= 0.01 or
|
has_activity = (
|
||||||
|
abs(data['opening_balance']) >= 0.01 or
|
||||||
abs(data['closing_balance']) >= 0.01 or
|
abs(data['closing_balance']) >= 0.01 or
|
||||||
abs(data['new_invoices']) >= 0.01 or
|
abs(data['new_invoices']) >= 0.01 or
|
||||||
abs(data['payments']) >= 0.01 or
|
abs(data['payments']) >= 0.01
|
||||||
abs(data['edv_daxil_18']) >= 0.01 or
|
)
|
||||||
abs(data['edv_azadolma']) >= 0.01 or
|
|
||||||
abs(data['edv_0']) >= 0.01 or
|
# Also check tax template activity
|
||||||
abs(data['edv_18']) >= 0.01):
|
for prefix in template_map.values():
|
||||||
|
if (abs(data[f'{prefix}_opening']) >= 0.01 or
|
||||||
|
abs(data[f'{prefix}_closing']) >= 0.01 or
|
||||||
|
abs(data[f'{prefix}_plus']) >= 0.01 or
|
||||||
|
abs(data[f'{prefix}_minus']) >= 0.01):
|
||||||
|
has_activity = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if has_activity:
|
||||||
result.append(data)
|
result.append(data)
|
||||||
|
|
||||||
return sorted(result, key=lambda x: x['customer'])
|
return sorted(result, key=lambda x: x['customer'])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue