def get_tax_details(doc_name): tax_amount = [] tax_details = { 'igst_amount': 0, 'cgst_amount': 0, 'sgst_amount': 0, 'cess_amount': 0, 'total_tax_amount': 0 } account_head_fields = [ 'igst_account', 'cgst_account', 'sgst_account', 'cess_account' ] doc = frappe.get_doc('Purchase Invoice', doc_name) gst_accounts = get_gst_accounts(doc.company) for row in doc.taxes: for accounts in gst_accounts.values(): if row.account_head in accounts: if not type(accounts[-1]) == float: accounts.append(0) accounts[-1] += row.tax_amount for idx in range(len(account_head_fields)): tax_amt = 0 if gst_accounts[account_head_fields[idx]][-1] and not type( gst_accounts[account_head_fields[idx]][-1]) == str: tax_amt = gst_accounts[account_head_fields[idx]][-1] tax_details[list(tax_details.keys())[idx]] = round(tax_amt, 2) tax_amount.append(tax_amt) tax_details['total_tax_amount'] = round(sum(tax_amount), 2) return tax_details
def update_invoice_taxes(invoice, invoice_value_details): gst_accounts = get_gst_accounts(invoice.company) gst_accounts_list = [ d for accounts in gst_accounts.values() for d in accounts if d ] invoice_value_details.total_cgst_amt = 0 invoice_value_details.total_sgst_amt = 0 invoice_value_details.total_igst_amt = 0 invoice_value_details.total_cess_amt = 0 invoice_value_details.total_other_charges = 0 for t in invoice.taxes: if t.account_head in gst_accounts_list: if t.account_head in gst_accounts.cess_account: # using after discount amt since item also uses after discount amt for cess calc invoice_value_details.total_cess_amt += abs( t.base_tax_amount_after_discount_amount) for tax_type in ['igst', 'cgst', 'sgst']: if t.account_head in gst_accounts['{}_account'.format( tax_type)]: invoice_value_details['total_{}_amt'.format( tax_type)] += abs( t.base_tax_amount_after_discount_amount) else: invoice_value_details.total_other_charges += abs( t.base_tax_amount_after_discount_amount) return invoice_value_details
def update_item_taxes(invoice, item): gst_accounts = get_gst_accounts(invoice.company) gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d] for attr in [ 'tax_rate', 'cess_rate', 'cess_nadv_amount', 'cgst_amount', 'sgst_amount', 'igst_amount', 'cess_amount', 'cess_nadv_amount', 'other_charges' ]: item[attr] = 0 for t in invoice.taxes: is_applicable = t.tax_amount and t.account_head in gst_accounts_list if is_applicable: # this contains item wise tax rate & tax amount (incl. discount) item_tax_detail = json.loads(t.item_wise_tax_detail).get(item.item_code) item_tax_rate = item_tax_detail[0] # item tax amount excluding discount amount item_tax_amount = (item_tax_rate / 100) * item.base_net_amount if t.account_head in gst_accounts.cess_account: item_tax_amount_after_discount = item_tax_detail[1] if t.charge_type == 'On Item Quantity': item.cess_nadv_amount += abs(item_tax_amount_after_discount) else: item.cess_rate += item_tax_rate item.cess_amount += abs(item_tax_amount_after_discount) for tax_type in ['igst', 'cgst', 'sgst']: if t.account_head in gst_accounts[f'{tax_type}_account']: item.tax_rate += item_tax_rate item[f'{tax_type}_amount'] += abs(item_tax_amount) return item
def update_invoice_taxes(invoice, invoice_value_details): gst_accounts = get_gst_accounts(invoice.company) gst_accounts_list = [d for accounts in gst_accounts.values() for d in accounts if d] invoice_value_details.total_cgst_amt = 0 invoice_value_details.total_sgst_amt = 0 invoice_value_details.total_igst_amt = 0 invoice_value_details.total_cess_amt = 0 invoice_value_details.total_other_charges = 0 considered_rows = [] for t in invoice.taxes: tax_amount = t.base_tax_amount if (invoice.apply_discount_on == 'Grand Total' and invoice.discount_amount) \ else t.base_tax_amount_after_discount_amount if t.account_head in gst_accounts_list: if t.account_head in gst_accounts.cess_account: # using after discount amt since item also uses after discount amt for cess calc invoice_value_details.total_cess_amt += abs(t.base_tax_amount_after_discount_amount) for tax_type in ['igst', 'cgst', 'sgst']: if t.account_head in gst_accounts[f'{tax_type}_account']: invoice_value_details[f'total_{tax_type}_amt'] += abs(tax_amount) update_other_charges(t, invoice_value_details, gst_accounts_list, invoice, considered_rows) else: invoice_value_details.total_other_charges += abs(tax_amount) return invoice_value_details
def run(self): self.get_columns() self.gst_accounts = get_gst_accounts(self.filters.company) self.get_invoice_data() if self.invoices: self.get_invoice_items() self.get_items_based_on_tax_rate() self.invoice_fields = [d["fieldname"] for d in self.invoice_columns] self.get_data() return self.columns, self.data
def get_hsn_wise_json_data(filters, report_data): filters = frappe._dict(filters) gst_accounts = get_gst_accounts(filters.company) data = [] count = 1 for hsn in report_data: row = { "num": count, "hsn_sc": hsn.get("gst_hsn_code"), "desc": hsn.get("description"), "uqc": hsn.get("stock_uom").upper(), "qty": hsn.get("stock_qty"), "val": flt(hsn.get("total_amount"), 2), "txval": flt(hsn.get("taxable_amount", 2)), "iamt": 0.0, "camt": 0.0, "samt": 0.0, "csamt": 0.0 } for account in gst_accounts.get('igst_account'): row['iamt'] += flt(hsn.get(frappe.scrub(cstr(account)), 0.0), 2) for account in gst_accounts.get('cgst_account'): row['camt'] += flt(hsn.get(frappe.scrub(cstr(account)), 0.0), 2) for account in gst_accounts.get('sgst_account'): row['samt'] += flt(hsn.get(frappe.scrub(cstr(account)), 0.0), 2) for account in gst_accounts.get('cess_account'): row['csamt'] += flt(hsn.get(frappe.scrub(cstr(account)), 0.0), 2) data.append(row) count +=1 return data
def execute(): company = frappe.get_all('Company', filters={'country': 'India'}, fields=['name']) if not company: return frappe.reload_doc("regional", "doctype", "gst_settings") frappe.reload_doc("accounts", "doctype", "gst_account") journal_entry_types = frappe.get_meta("Journal Entry").get_options( "voucher_type").split("\n") + ['Reversal Of ITC'] make_property_setter('Journal Entry', 'voucher_type', 'options', '\n'.join(journal_entry_types), '') custom_fields = { 'Journal Entry': [ dict( fieldname='reversal_type', label='Reversal Type', fieldtype='Select', insert_after='voucher_type', print_hide=1, options="As per rules 42 & 43 of CGST Rules\nOthers", depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'" ), dict( fieldname='company_address', label='Company Address', fieldtype='Link', options='Address', insert_after='reversal_type', print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'" ), dict( fieldname='company_gstin', label='Company GSTIN', fieldtype='Data', read_only=1, insert_after='company_address', print_hide=1, fetch_from='company_address.gstin', depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'" ) ], 'Purchase Invoice': [ dict( fieldname='eligibility_for_itc', label='Eligibility For ITC', fieldtype='Select', insert_after='reason_for_issuing_document', print_hide=1, options= 'Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC', default="All Other ITC") ], 'Purchase Invoice Item': [ dict(fieldname='taxable_value', label='Taxable Value', fieldtype='Currency', insert_after='base_net_amount', hidden=1, options="Company:company:default_currency", print_hide=1) ] } create_custom_fields(custom_fields, update=True) # Patch ITC Availed fields from Data to Currency # Patch Availed ITC for current fiscal_year gst_accounts = get_gst_accounts(only_non_reverse_charge=1) frappe.db.sql(""" UPDATE `tabCustom Field` SET fieldtype='Currency', options='Company:company:default_currency' WHERE dt = 'Purchase Invoice' and fieldname in ('itc_integrated_tax', 'itc_state_tax', 'itc_central_tax', 'itc_cess_amount') """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_integrated_tax = '0' WHERE trim(coalesce(itc_integrated_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_state_tax = '0' WHERE trim(coalesce(itc_state_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_central_tax = '0' WHERE trim(coalesce(itc_central_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_cess_amount = '0' WHERE trim(coalesce(itc_cess_amount, '')) = '' """) # Get purchase invoices invoices = frappe.get_all( 'Purchase Invoice', { 'posting_date': ('>=', '2021-04-01'), 'eligibility_for_itc': ('!=', 'Ineligible') }, ['name']) amount_map = {} if invoices: invoice_list = set([d.name for d in invoices]) # Get GST applied amounts = frappe.db.sql(""" SELECT parent, account_head, sum(base_tax_amount_after_discount_amount) as amount FROM `tabPurchase Taxes and Charges` where parent in %s GROUP BY parent, account_head """, (invoice_list), as_dict=1) for d in amounts: amount_map.setdefault( d.parent, { 'itc_integrated_tax': 0, 'itc_state_tax': 0, 'itc_central_tax': 0, 'itc_cess_amount': 0 }) if d.account_head in gst_accounts.get('igst_account'): amount_map[d.parent]['itc_integrated_tax'] += d.amount if d.account_head in gst_accounts.get('cgst_account'): amount_map[d.parent]['itc_central_tax'] += d.amount if d.account_head in gst_accounts.get('sgst_account'): amount_map[d.parent]['itc_state_tax'] += d.amount if d.account_head in gst_accounts.get('cess_account'): amount_map[d.parent]['itc_cess_amount'] += d.amount for invoice, values in amount_map.items(): frappe.db.set_value( 'Purchase Invoice', invoice, { 'itc_integrated_tax': values.get('itc_integrated_tax'), 'itc_central_tax': values.get('itc_central_tax'), 'itc_state_tax': values['itc_state_tax'], 'itc_cess_amount': values['itc_cess_amount'], })
def calculate_amounts(dt, dn): #TODO: redo this with and get tax rate from internal function and taxable from the below method. hsn_list = [] total_list = {} hsn_taxable_amount_list = {} total_taxable_amount_set = {'bool': 0} total_taxable_amount = {'amount': 0.0} total_discount = {'amount': 0.0} cgst_rate = [] sgst_rate = [] igst_rate = [] cgst_amount = [] sgst_amount = [] igst_amount = [] itemList = [] dn = json.loads(dn) sinv_doc = frappe.get_doc(dt, dn[0]) gst_account_heads = get_gst_accounts(sinv_doc.company, True) for row in sinv_doc.items: if row.gst_hsn_code not in hsn_list: hsn_list.append(row.gst_hsn_code) for hsn in hsn_list: total_list.update({hsn: 0}) total_list.update({hsn: total_list[hsn] + 1}) total_list.update({hsn: total_list[hsn] - 1}) for row in sinv_doc.items: total_list.update( {row.gst_hsn_code: total_list[row.gst_hsn_code] + row.amount}) for row in sinv_doc.taxes: if row.account_head in gst_account_heads: if total_taxable_amount_set['bool'] == 0: total_taxable_amount_set.update({'bool': 1}) total_taxable_amount.update( {'amount': row.total - row.tax_amount}) if gst_account_heads[row.account_head] == 'cgst_account': cgst_amount.append(row.tax_amount * 1.0) cgst_rate.append( (row.tax_amount / (total_taxable_amount['amount'])) * 100) elif gst_account_heads[row.account_head] == 'sgst_account': sgst_amount.append(row.tax_amount * 1.0) sgst_rate.append( (row.tax_amount / (total_taxable_amount['amount'])) * 100) elif gst_account_heads[row.account_head] == 'igst_account': igst_amount.append(row.tax_amount * 1.0) igst_rate.append( (row.tax_amount / (total_taxable_amount['amount'])) * 100) if not cgst_rate: cgst_rate.append(0) if not sgst_rate: sgst_rate.append(0) if not igst_rate: igst_rate.append(0) total_discount.update( {'amount': sinv_doc.total - total_taxable_amount['amount']}) for hsn in hsn_list: temp = total_list[hsn] - ( (total_list[hsn] / sinv_doc.total) * total_discount['amount']) hsn_taxable_amount_list.update({hsn: temp}) for hsn in hsn_list: item = { 'hsnCode': hsn, 'cgstRate': round(cgst_rate[0], 2), 'sgstRate': round(sgst_rate[0], 2), 'igstRate': round(igst_rate[0], 2), 'taxableAmount': round(hsn_taxable_amount_list[hsn], 2) } itemList.append(item) return { 'totInvValue': sinv_doc.grand_total, 'totalValue': total_taxable_amount['amount'], 'cgstValue': sum(cgst_amount), 'sgstValue': sum(sgst_amount), 'igstValue': sum(igst_amount), 'OthValue': sinv_doc.grand_total - (total_taxable_amount['amount'] + sum(cgst_amount) + sum(sgst_amount) + sum(igst_amount)), 'itemList': itemList }
def calculate_amounts(dt, dn): dn = json.loads(dn) sinv_doc = frappe.get_doc(dt, dn[0]) gst_account_heads = get_gst_accounts(sinv_doc.company, True) cgstValue = 0 sgstValue = 0 igstValue = 0 for row in sinv_doc.taxes: if row.account_head in gst_account_heads: if gst_account_heads[row.account_head] == 'cgst_account': cgstValue += row.tax_amount elif gst_account_heads[row.account_head] == 'sgst_account': sgstValue += row.tax_amount elif gst_account_heads[row.account_head] == 'igst_account': igstValue += row.tax_amount else: # raising this error because this function might be irrelavant if cess is applied... # not sure... have to check when we get the error... frappe.throw(_(f'Unsupported tax account type: {gst_account_heads[row.account_head]}. Please Contact Admin.')) taxable_value = sinv_doc.grand_total - (cgstValue + sgstValue + igstValue) taxable_value_from_item_list = sinv_doc.total discount_value = taxable_value_from_item_list - taxable_value tax_breakup_default = get_itemised_tax_breakup_data(sinv_doc, True) itemList = [] for hsn, hsn_detail in tax_breakup_default[0].items(): cgstRate = 0 sgstRate = 0 igstRate = 0 for account_head, details in hsn_detail.items(): if account_head in gst_account_heads: if gst_account_heads[account_head] == 'cgst_account': cgstRate = details['tax_rate'] elif gst_account_heads[account_head] == 'sgst_account': sgstRate = details['tax_rate'] elif gst_account_heads[account_head] == 'igst_account': igstRate = details['tax_rate'] else: # raising this error because this function might be irrelavant if cess is applied... # not sure... have to check when we get the error... frappe.throw(_('Unsupported tax account type: {gst_account_heads[row.account_head]}. Please Contact Admin.')) hsn_total_amount = tax_breakup_default[1][hsn] taxableAmount = hsn_total_amount - ((hsn_total_amount / taxable_value_from_item_list) * discount_value) item = { 'hsnCode': hsn, 'cgstRate': cgstRate, 'sgstRate': sgstRate, 'igstRate': igstRate, 'taxableAmount': taxableAmount } itemList.append(item) return { 'totInvValue': sinv_doc.grand_total, 'totalValue': taxable_value, 'cgstValue': cgstValue, 'sgstValue': sgstValue, 'igstValue': igstValue, 'OthValue': 0, 'itemList': itemList }
def execute(): company = frappe.get_all("Company", filters={"country": "India"}, fields=["name"]) if not company: return frappe.reload_doc("regional", "doctype", "gst_settings") frappe.reload_doc("accounts", "doctype", "gst_account") journal_entry_types = frappe.get_meta("Journal Entry").get_options( "voucher_type").split("\n") + ["Reversal Of ITC"] make_property_setter("Journal Entry", "voucher_type", "options", "\n".join(journal_entry_types), "") custom_fields = { "Journal Entry": [ dict( fieldname="reversal_type", label="Reversal Type", fieldtype="Select", insert_after="voucher_type", print_hide=1, options="As per rules 42 & 43 of CGST Rules\nOthers", depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), dict( fieldname="company_address", label="Company Address", fieldtype="Link", options="Address", insert_after="reversal_type", print_hide=1, depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), dict( fieldname="company_gstin", label="Company GSTIN", fieldtype="Data", read_only=1, insert_after="company_address", print_hide=1, fetch_from="company_address.gstin", depends_on="eval:doc.voucher_type=='Reversal Of ITC'", mandatory_depends_on="eval:doc.voucher_type=='Reversal Of ITC'", ), ], "Purchase Invoice": [ dict( fieldname="eligibility_for_itc", label="Eligibility For ITC", fieldtype="Select", insert_after="reason_for_issuing_document", print_hide=1, options= "Input Service Distributor\nImport Of Service\nImport Of Capital Goods\nITC on Reverse Charge\nIneligible As Per Section 17(5)\nIneligible Others\nAll Other ITC", default="All Other ITC", ) ], "Purchase Invoice Item": [ dict( fieldname="taxable_value", label="Taxable Value", fieldtype="Currency", insert_after="base_net_amount", hidden=1, options="Company:company:default_currency", print_hide=1, ) ], } create_custom_fields(custom_fields, update=True) # Patch ITC Availed fields from Data to Currency # Patch Availed ITC for current fiscal_year gst_accounts = get_gst_accounts(only_non_reverse_charge=1) frappe.db.sql(""" UPDATE `tabCustom Field` SET fieldtype='Currency', options='Company:company:default_currency' WHERE dt = 'Purchase Invoice' and fieldname in ('itc_integrated_tax', 'itc_state_tax', 'itc_central_tax', 'itc_cess_amount') """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_integrated_tax = '0' WHERE trim(coalesce(itc_integrated_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_state_tax = '0' WHERE trim(coalesce(itc_state_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_central_tax = '0' WHERE trim(coalesce(itc_central_tax, '')) = '' """) frappe.db.sql("""UPDATE `tabPurchase Invoice` set itc_cess_amount = '0' WHERE trim(coalesce(itc_cess_amount, '')) = '' """) # Get purchase invoices invoices = frappe.get_all( "Purchase Invoice", { "posting_date": (">=", "2021-04-01"), "eligibility_for_itc": ("!=", "Ineligible") }, ["name"], ) amount_map = {} if invoices: invoice_list = set([d.name for d in invoices]) # Get GST applied amounts = frappe.db.sql( """ SELECT parent, account_head, sum(base_tax_amount_after_discount_amount) as amount FROM `tabPurchase Taxes and Charges` where parent in %s GROUP BY parent, account_head """, (invoice_list), as_dict=1, ) for d in amounts: amount_map.setdefault( d.parent, { "itc_integrated_tax": 0, "itc_state_tax": 0, "itc_central_tax": 0, "itc_cess_amount": 0 }, ) if not gst_accounts: continue if d.account_head in gst_accounts.get("igst_account"): amount_map[d.parent]["itc_integrated_tax"] += d.amount if d.account_head in gst_accounts.get("cgst_account"): amount_map[d.parent]["itc_central_tax"] += d.amount if d.account_head in gst_accounts.get("sgst_account"): amount_map[d.parent]["itc_state_tax"] += d.amount if d.account_head in gst_accounts.get("cess_account"): amount_map[d.parent]["itc_cess_amount"] += d.amount for invoice, values in amount_map.items(): frappe.db.set_value( "Purchase Invoice", invoice, { "itc_integrated_tax": values.get("itc_integrated_tax"), "itc_central_tax": values.get("itc_central_tax"), "itc_state_tax": values["itc_state_tax"], "itc_cess_amount": values["itc_cess_amount"], }, )