├── india_compliance
├── public
│ ├── .gitkeep
│ ├── images
│ │ ├── mail-box.png
│ │ └── india-compliance-logo.png
│ └── js
│ │ ├── gstr1.bundle.js
│ │ ├── india_compliance_account
│ │ ├── utils.js
│ │ ├── constants.js
│ │ ├── store
│ │ │ └── index.js
│ │ ├── components
│ │ │ ├── PageTitle.vue
│ │ │ ├── PreLoader.vue
│ │ │ ├── Message.vue
│ │ │ ├── auth
│ │ │ │ └── MarketingInfoCheckIcon.vue
│ │ │ ├── Loading.vue
│ │ │ ├── invoice_history_table.html
│ │ │ └── TheFooter.vue
│ │ ├── pages
│ │ │ └── PageNotFound.vue
│ │ ├── router.js
│ │ └── services
│ │ │ ├── AccountService.js
│ │ │ └── AuthService.js
│ │ ├── ims.bundle.js
│ │ ├── purchase_reconciliation_tool.bundle.js
│ │ ├── india_compliance.bundle.js
│ │ ├── custom_number_card.js
│ │ ├── components
│ │ ├── set_gstin_options.js
│ │ └── number_card.js
│ │ ├── regex_constants.js
│ │ ├── new_gst_category_notification.js
│ │ └── quick_info_popover.js
├── www
│ └── __init__.py
├── config
│ ├── __init__.py
│ ├── docs.py
│ └── desktop.py
├── gst_india
│ ├── __init__.py
│ ├── page
│ │ ├── __init__.py
│ │ └── india_compliance_account
│ │ │ ├── india_compliance_account.js
│ │ │ └── india_compliance_account.json
│ ├── doctype
│ │ ├── __init__.py
│ │ ├── gstin
│ │ │ ├── __init__.py
│ │ │ ├── gstin.js
│ │ │ └── test_gstin.py
│ │ ├── gstr_1
│ │ │ ├── __init__.py
│ │ │ └── test_gstr_1.py
│ │ ├── pan
│ │ │ ├── __init__.py
│ │ │ ├── test_pan.py
│ │ │ ├── pan.js
│ │ │ └── pan.json
│ │ ├── gst_account
│ │ │ ├── __init__.py
│ │ │ └── gst_account.py
│ │ ├── gst_uom_map
│ │ │ ├── __init__.py
│ │ │ ├── gst_uom_map.py
│ │ │ └── gst_uom_map.json
│ │ ├── gstr_action
│ │ │ ├── __init__.py
│ │ │ ├── gstr_action.py
│ │ │ └── gstr_action.json
│ │ ├── bill_of_entry
│ │ │ └── __init__.py
│ │ ├── e_invoice_log
│ │ │ ├── __init__.py
│ │ │ ├── e_invoice_log.js
│ │ │ ├── test_e_invoice_log.py
│ │ │ ├── e_invoice_log.py
│ │ │ └── e_invoice_log_list.js
│ │ ├── e_waybill_log
│ │ │ ├── __init__.py
│ │ │ ├── e_waybill_log.js
│ │ │ ├── test_e_waybill_log.py
│ │ │ ├── e_waybill_log_list.js
│ │ │ └── e_waybill_log.py
│ │ ├── gst_credential
│ │ │ ├── __init__.py
│ │ │ └── gst_credential.py
│ │ ├── gst_hsn_code
│ │ │ ├── __init__.py
│ │ │ ├── gst_hsn_code.js
│ │ │ └── gst_hsn_code.json
│ │ ├── gst_return_log
│ │ │ ├── __init__.py
│ │ │ └── test_gst_return_log.py
│ │ ├── gst_settings
│ │ │ └── __init__.py
│ │ ├── gstr_3b_report
│ │ │ ├── __init__.py
│ │ │ └── gstr_3b_report_list.js
│ │ ├── gstr_import_log
│ │ │ ├── __init__.py
│ │ │ ├── gstr_import_log.js
│ │ │ └── test_gstr_import_log.py
│ │ ├── bill_of_entry_item
│ │ │ ├── __init__.py
│ │ │ └── bill_of_entry_item.py
│ │ ├── company_print_options
│ │ │ ├── __init__.py
│ │ │ ├── company_print_options.py
│ │ │ └── company_print_options.json
│ │ ├── gst_inward_supply
│ │ │ ├── __init__.py
│ │ │ ├── gst_inward_supply.js
│ │ │ └── test_gst_inward_supply.py
│ │ ├── gst_inward_supply_item
│ │ │ ├── __init__.py
│ │ │ ├── gst_inward_supply_item.py
│ │ │ └── gst_inward_supply_item.json
│ │ ├── e_invoice_applicable_company
│ │ │ ├── __init__.py
│ │ │ ├── e_invoice_applicable_company.py
│ │ │ └── e_invoice_applicable_company.json
│ │ ├── india_compliance_taxes_and_charges
│ │ │ ├── __init__.py
│ │ │ └── india_compliance_taxes_and_charges.py
│ │ └── purchase_reconciliation_tool
│ │ │ └── gstr_download_history.html
│ ├── overrides
│ │ ├── __init__.py
│ │ ├── cross_app_hsn_code.py
│ │ ├── email_template.py
│ │ ├── test_setup_wizard.py
│ │ ├── tax_category.py
│ │ ├── gl_entry.py
│ │ ├── test_party.py
│ │ ├── journal_entry.py
│ │ ├── test_sales_invoice.py
│ │ ├── unreconcile_payment.py
│ │ ├── item.py
│ │ ├── delivery_note.py
│ │ └── purchase_receipt.py
│ ├── report
│ │ ├── __init__.py
│ │ ├── gst_balance
│ │ │ ├── __init__.py
│ │ │ └── gst_balance.json
│ │ ├── gstin_status
│ │ │ ├── __init__.py
│ │ │ └── gstin_status.json
│ │ ├── e_invoice_summary
│ │ │ ├── __init__.py
│ │ │ └── e_invoice_summary.json
│ │ ├── gstr_3b_details
│ │ │ ├── __init__.py
│ │ │ └── gstr_3b_details.json
│ │ ├── bill_of_entry_summary
│ │ │ ├── __init__.py
│ │ │ ├── bill_of_entry_summary.json
│ │ │ └── bill_of_entry_summary.js
│ │ ├── gst_advance_detail
│ │ │ ├── __init__.py
│ │ │ └── gst_advance_detail.json
│ │ ├── gst_purchase_register
│ │ │ ├── __init__.py
│ │ │ └── gst_purchase_register.json
│ │ ├── gst_sales_register
│ │ │ ├── __init__.py
│ │ │ └── gst_sales_register.json
│ │ ├── summary_of_itc_availed
│ │ │ ├── __init__.py
│ │ │ └── summary_of_itc_availed.json
│ │ ├── gst_account_wise_summary
│ │ │ ├── __init__.py
│ │ │ └── gst_account_wise_summary.json
│ │ ├── gst_job_work_stock_movement
│ │ │ ├── __init__.py
│ │ │ └── gst_job_work_stock_movement.json
│ │ ├── gst_tax_rate_wise_summary
│ │ │ ├── __init__.py
│ │ │ └── gst_tax_rate_wise_summary.json
│ │ ├── india_compliance_api_usage
│ │ │ ├── __init__.py
│ │ │ ├── india_compliance_api_usage.json
│ │ │ └── india_compliance_api_usage.js
│ │ ├── hsn_wise_summary_of_inward_supplies
│ │ │ ├── __init__.py
│ │ │ ├── hsn_wise_summary_of_inward_supplies.py
│ │ │ └── hsn_wise_summary_of_inward_supplies.json
│ │ ├── hsn_wise_summary_of_outward_supplies
│ │ │ ├── __init__.py
│ │ │ └── hsn_wise_summary_of_outward_supplies.json
│ │ └── utils.js
│ ├── api_classes
│ │ ├── __init__.py
│ │ └── nic
│ │ │ └── __init__.py
│ ├── print_format
│ │ ├── __init__.py
│ │ ├── e_invoice
│ │ │ ├── __init__.py
│ │ │ ├── e_invoice.css
│ │ │ └── e_invoice.json
│ │ ├── e_waybill
│ │ │ ├── __init__.py
│ │ │ └── e_waybill.json
│ │ ├── gst_pos_invoice
│ │ │ └── __init__.py
│ │ ├── gst_tax_invoice
│ │ │ └── __init__.py
│ │ ├── e_waybill_detailed
│ │ │ ├── __init__.py
│ │ │ └── e_waybill_detailed.json
│ │ └── gst_purchase_invoice
│ │ │ └── __init__.py
│ ├── web_template
│ │ ├── __init__.py
│ │ ├── upi_qr_code
│ │ │ ├── __init__.py
│ │ │ ├── upi_qr_code.html
│ │ │ └── upi_qr_code.json
│ │ └── e_invoice_qr
│ │ │ ├── __init__.py
│ │ │ ├── e_invoice_qr.html
│ │ │ └── e_invoice_qr.json
│ ├── data
│ │ ├── gstr1_excel_template_v2.0.xlsx
│ │ ├── gstr1_excel_template_v2.1.xlsx
│ │ ├── gstr3b_excel_utility_v5.7.xlsx
│ │ └── address_template.html
│ ├── constants
│ │ └── e_invoice.py
│ ├── client_scripts
│ │ ├── document_naming_settings.js
│ │ ├── document_naming_rule.js
│ │ ├── customer.js
│ │ ├── expense_claim.js
│ │ ├── item.js
│ │ ├── subcontracting_order.js
│ │ ├── supplier.js
│ │ ├── delivery_note.js
│ │ ├── purchase_receipt.js
│ │ └── journal_entry.js
│ ├── number_card
│ │ ├── pending_e_waybill
│ │ │ └── pending_e_waybill.json
│ │ ├── pending_e_invoices
│ │ │ └── pending_e_invoices.json
│ │ └── invoice_cancelled_but_not_e_invoice
│ │ │ └── invoice_cancelled_but_not_e_invoice.json
│ └── utils
│ │ └── api.py
├── patches
│ ├── __init__.py
│ ├── v14
│ │ ├── __init__.py
│ │ ├── set_default_for_overridden_accounts_setting.py
│ │ ├── set_sandbox_mode_in_gst_settings.py
│ │ ├── update_default_e_invoice_time_limit.py
│ │ ├── remove_ecommerce_gstin_from_purchase_invoice.py
│ │ ├── update_gstin_status_refresh_interval.py
│ │ ├── delete_not_generated_gstr_import_log.py
│ │ ├── rename_reverse_charge_to_purchase_reverse_charge.py
│ │ ├── update_default_gstr1_settings.py
│ │ ├── rename_gstr1_settings.py
│ │ ├── delete_purchase_receipt_standard_custom_fields.py
│ │ ├── update_purchase_reco_email_template.py
│ │ ├── update_default_auto_reconciliation_settings.py
│ │ ├── enable_sales_through_ecommerce_operator.py
│ │ ├── set_autogenerate_e_waybill_with_e_invoice.py
│ │ ├── update_tax_withholding_categories.py
│ │ ├── stop_unnecessary_scheduled_jobs.py
│ │ ├── set_reverse_charge_applicability_in_supplier.py
│ │ ├── set_enable_retry_einv_ewb_generation.py
│ │ ├── set_item_details_from_purchase_invoice_to_bill_of_entry.py
│ │ ├── unset_inward_supply_link_for_cancelled_purchase.py
│ │ ├── update_e_invoice_status.py
│ │ ├── add_match_found_in_purchase_reconciliation_status.py
│ │ ├── set_default_for_audit_trail_notification.py
│ │ ├── update_total_taxes_for_gst_inward_supply.py
│ │ ├── set_pending_boe_qty.py
│ │ ├── set_reconciliation_status_for_manual_match.py
│ │ └── set_correct_root_account_for_rcm.py
│ ├── v15
│ │ ├── __init__.py
│ │ ├── unset_auth_token.py
│ │ ├── set_default_hsn_bifurcation_date.py
│ │ ├── update_supplier_filing_status.py
│ │ ├── make_e_invoice_log_extensible.py
│ │ ├── remove_duplicate_web_template.py
│ │ ├── update_action_for_gst_inward_supply.py
│ │ ├── migrate_print_options_to_new_field.py
│ │ ├── remove_itc_amount_custom_fields.py
│ │ ├── multiple_pi_in_boe.py
│ │ ├── set_default_for_new_gst_category_notification.py
│ │ ├── remove_ignore_reconciliation_field.py
│ │ ├── migrate_gstr1_log_to_returns_log.py
│ │ ├── set_download_document_for_2a_2b.py
│ │ ├── update_action_for_rejected_invoices_in_gst_inward_supply.py
│ │ ├── update_return_logs_with_filing_preference.py
│ │ └── migrate_boe_taxes_to_ic_taxes.py
│ ├── post_install
│ │ ├── __init__.py
│ │ ├── update_custom_role_for_e_invoice_summary.py
│ │ ├── update_default_gstr3b_status.py
│ │ ├── update_state_name_to_puducherry.py
│ │ ├── update_tax_category_for_rcm.py
│ │ ├── remove_consumer_gst_category.py
│ │ ├── update_state_code_for_daman_and_diu.py
│ │ ├── rename_import_of_capital_goods.py
│ │ ├── update_gst_category.py
│ │ ├── update_payment_entry_fields.py
│ │ ├── remove_deprecated_docs.py
│ │ ├── update_vehicle_no_field_in_purchase_receipt.py
│ │ ├── add_company_link_to_einvoice_settings.py
│ │ ├── setup_custom_fields_for_gst.py
│ │ ├── set_gst_tax_type_in_journal_entry.py
│ │ ├── migrate_fields_for_gstr3b.py
│ │ ├── update_reverse_charge_and_export_type.py
│ │ ├── manual_patch_to_update_gst_details.py
│ │ ├── remove_old_fields.py
│ │ ├── update_reconciliation_status.py
│ │ ├── merge_utgst_account_into_sgst_account.py
│ │ ├── set_gst_tax_type.py
│ │ ├── set_gst_category.py
│ │ ├── update_gst_treatment_for_taxable_nil_transaction_item.py
│ │ └── update_itc_classification_field.py
│ └── v16
│ │ └── remove_legacy_report_fixtures.py
├── templates
│ ├── __init__.py
│ └── pages
│ │ └── __init__.py
├── utils
│ └── __init__.py
├── vat_india
│ ├── __init__.py
│ └── doctype
│ │ ├── __init__.py
│ │ ├── c_form
│ │ ├── __init__.py
│ │ ├── README.md
│ │ ├── test_c_form.py
│ │ └── c_form.js
│ │ └── c_form_invoice_detail
│ │ ├── __init__.py
│ │ ├── README.md
│ │ └── c_form_invoice_detail.py
├── audit_trail
│ ├── __init__.py
│ ├── report
│ │ ├── __init__.py
│ │ └── audit_trail
│ │ │ ├── __init__.py
│ │ │ └── audit_trail.json
│ ├── constants
│ │ ├── __init__.py
│ │ └── custom_fields.py
│ ├── client_scripts
│ │ └── customize_form.js
│ ├── overrides
│ │ ├── version.py
│ │ ├── test_account_settings.py
│ │ ├── test_customize_form.py
│ │ ├── accounts_settings.py
│ │ ├── customize_form.py
│ │ ├── property_setter.py
│ │ ├── test_version.py
│ │ └── test_property_setter.py
│ ├── utils.py
│ └── setup.py
├── income_tax_india
│ ├── __init__.py
│ ├── doctype
│ │ └── __init__.py
│ ├── uninstall.py
│ ├── setup.py
│ ├── overrides
│ │ └── tax_withholding_category.py
│ └── constants
│ │ └── __init__.py
├── modules.txt
├── __init__.py
├── exceptions.py
├── test_patches.py
└── uninstall.py
├── .prettierrc.yaml
├── setup.py
├── .github
├── dependabot.yml
├── helper
│ └── site_config.json
├── workflows
│ ├── docs-required.yml
│ ├── linters.yml
│ ├── initiate_release.yml
│ ├── semantic-commits.yml
│ └── on_release.yml
└── ISSUE_TEMPLATE
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .prettierignore
├── MANIFEST.in
├── commitlint.config.js
├── codecov.yml
├── .releaserc
├── .git-blame-ignore-revs
├── pyproject.toml
├── .pre-commit-config.yaml
└── .flake8
/india_compliance/public/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/www/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/config/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/patches/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/templates/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/page/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/report/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/templates/pages/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/constants/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/api_classes/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstin/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_1/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/pan/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/doctype/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/api_classes/nic/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_account/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_uom_map/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_action/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_balance/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gstin_status/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/report/audit_trail/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/bill_of_entry/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_waybill_log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_credential/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_hsn_code/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_return_log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_settings/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_3b_report/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_import_log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_invoice/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_waybill/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/e_invoice_summary/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gstr_3b_details/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/upi_qr_code/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/bill_of_entry_item/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/company_print_options/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/gst_pos_invoice/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/gst_tax_invoice/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/bill_of_entry_summary/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_advance_detail/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_purchase_register/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_sales_register/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/summary_of_itc_availed/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/e_invoice_qr/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form_invoice_detail/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply_item/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_waybill_detailed/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/gst_purchase_invoice/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_account_wise_summary/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_job_work_stock_movement/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_tax_rate_wise_summary/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/india_compliance_api_usage/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | tabWidth: 4
2 | printWidth: 88
3 | arrowParens: "avoid"
4 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_applicable_company/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/india_compliance_taxes_and_charges/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/hsn_wise_summary_of_inward_supplies/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/hsn_wise_summary_of_outward_supplies/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/modules.txt:
--------------------------------------------------------------------------------
1 | GST India
2 | Income Tax India
3 | VAT India
4 | Audit Trail
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | name = "india_compliance"
4 |
5 | setup()
6 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form/README.md:
--------------------------------------------------------------------------------
1 | C Form (India specific only) - Will be deprecated.
2 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form_invoice_detail/README.md:
--------------------------------------------------------------------------------
1 | Invoice detail for parent C-Form.
2 |
--------------------------------------------------------------------------------
/india_compliance/public/images/mail-box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/resilient-tech/india-compliance/HEAD/india_compliance/public/images/mail-box.png
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/upi_qr_code/upi_qr_code.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/e_invoice_qr/e_invoice_qr.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/india_compliance/public/js/gstr1.bundle.js:
--------------------------------------------------------------------------------
1 | import "./components/filter_group";
2 | import "./components/data_table_manager";
3 | import "./components/view_group";
4 |
--------------------------------------------------------------------------------
/india_compliance/public/images/india-compliance-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/resilient-tech/india-compliance/HEAD/india_compliance/public/images/india-compliance-logo.png
--------------------------------------------------------------------------------
/india_compliance/patches/v15/unset_auth_token.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_value("GST Credential", {"service": "Returns"}, "auth_token", None)
6 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/utils.js:
--------------------------------------------------------------------------------
1 | export const getReadableNumber = function (num, precision = 2) {
2 | return format_number(num, null, precision);
3 | };
4 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/data/gstr1_excel_template_v2.0.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/resilient-tech/india-compliance/HEAD/india_compliance/gst_india/data/gstr1_excel_template_v2.0.xlsx
--------------------------------------------------------------------------------
/india_compliance/gst_india/data/gstr1_excel_template_v2.1.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/resilient-tech/india-compliance/HEAD/india_compliance/gst_india/data/gstr1_excel_template_v2.1.xlsx
--------------------------------------------------------------------------------
/india_compliance/gst_india/data/gstr3b_excel_utility_v5.7.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/resilient-tech/india-compliance/HEAD/india_compliance/gst_india/data/gstr3b_excel_utility_v5.7.xlsx
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_default_for_overridden_accounts_setting.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_default("add_taxes_from_item_tax_template", 0)
6 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/constants.js:
--------------------------------------------------------------------------------
1 | export const UiState = Object.freeze({
2 | initial: 0,
3 | loading: 1,
4 | success: 2,
5 | error: 3,
6 | });
7 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/set_default_hsn_bifurcation_date.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_single_value("GST Settings", "hsn_bifurcation_from", "2025-04-01")
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.pyc
3 | *.egg-info
4 | *.swp
5 | tags
6 | .vscode/
7 | __pycache__/
8 |
9 | # docs
10 | india_compliance/docs/current
11 |
12 | # JS
13 | dist/
14 | node_modules
15 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/cross_app_hsn_code.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def before_update(doc, method=None):
5 | if doc.gst_hsn_code:
6 | frappe.flags.cross_app_hsn_code = doc.gst_hsn_code
7 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/constants/e_invoice.py:
--------------------------------------------------------------------------------
1 | CANCEL_REASON_CODES = {
2 | "Duplicate": "1",
3 | "Order Cancelled": "3",
4 | "Data Entry Mistake": "2",
5 | "Others": "4",
6 | }
7 |
8 | ITEM_LIMIT = 1000
9 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_sandbox_mode_in_gst_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if frappe.conf.ic_api_sandbox_mode:
6 | frappe.db.set_single_value("GST Settings", "sandbox_mode", 1)
7 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_default_e_invoice_time_limit.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_single_value(
6 | "GST Settings", {"e_invoice_reporting_time_limit_days": 30}
7 | )
8 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/remove_ecommerce_gstin_from_purchase_invoice.py:
--------------------------------------------------------------------------------
1 | from india_compliance.utils.custom_fields import delete_old_fields
2 |
3 |
4 | def execute():
5 | delete_old_fields("ecommerce_gstin", "Purchase Invoice")
6 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_custom_role_for_e_invoice_summary.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_value(
6 | "Custom Role", {"report": "E-Invoice Summary"}, "report", "e-Invoice Summary"
7 | )
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Ignore files with {% include ... %}
2 | india_compliance/income_tax_india/report/income_tax_deductions/income_tax_deductions.js
3 |
4 | # JSON files - most are autogenerated
5 | *.json
6 |
7 | # Other
8 | node_modules
9 | dist/
10 |
--------------------------------------------------------------------------------
/india_compliance/public/js/ims.bundle.js:
--------------------------------------------------------------------------------
1 | import "./components/data_table_manager";
2 | import "./components/number_card";
3 | import "./components/set_gstin_options";
4 | import "./components/filter_group";
5 | import "./reconciliation_components/actions";
6 |
--------------------------------------------------------------------------------
/india_compliance/public/js/purchase_reconciliation_tool.bundle.js:
--------------------------------------------------------------------------------
1 | import "./gstr_2b";
2 | import "./components/data_table_manager";
3 | import "./components/filter_group";
4 | import "./components/number_card";
5 | import "./reconciliation_components/actions";
6 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/pan/test_pan.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TestPAN(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_log/e_invoice_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on('e-Invoice Log', {
5 | // refresh: function(frm) {
6 |
7 | // }
8 | // });
9 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_waybill_log/e_waybill_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on('e-Waybill Log', {
5 | // refresh: function(frm) {
6 |
7 | // }
8 | // });
9 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_1/test_gstr_1.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TestGSTR1(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_import_log/gstr_import_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('GSTR Import Log', {
5 | // refresh: function(frm) {
6 |
7 | // }
8 | });
9 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply/gst_inward_supply.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('GST Inward Supply', {
5 | // refresh: function(frm) {
6 |
7 | // }
8 | });
9 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/uninstall.py:
--------------------------------------------------------------------------------
1 | from india_compliance.income_tax_india.constants.custom_fields import CUSTOM_FIELDS
2 | from india_compliance.utils.custom_fields import delete_custom_fields
3 |
4 |
5 | def before_uninstall():
6 | delete_custom_fields(CUSTOM_FIELDS)
7 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_default_gstr3b_status.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | doc = frappe.qb.DocType("GSTR 3B Report")
6 | frappe.qb.update(doc).set(doc.generation_status, "Generated").where(
7 | doc.generation_status.isnull()
8 | ).run()
9 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_gstin_status_refresh_interval.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if frappe.db.get_single_value("GST Settings", "gstin_status_refresh_interval") < 15:
6 | frappe.db.set_single_value("GST Settings", "gstin_status_refresh_interval", 15)
7 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_log/test_e_invoice_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TesteInvoiceLog(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_waybill_log/test_e_waybill_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TesteWaybillLog(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_return_log/test_gst_return_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TestGSTReturnLog(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_account/gst_account.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 |
5 | from frappe.model.document import Document
6 |
7 |
8 | class GSTAccount(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_uom_map/gst_uom_map.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class GSTUOMMap(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_import_log/test_gstr_import_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TestGSTRImportLog(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/delete_not_generated_gstr_import_log.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.delete(
6 | "GSTR Import Log",
7 | filters={
8 | "data_not_found": 1,
9 | "return_type": "GSTR2b",
10 | },
11 | )
12 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_log/e_invoice_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class eInvoiceLog(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply/test_gst_inward_supply.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase
6 |
7 |
8 | class TestGSTInwardSupply(IntegrationTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/document_naming_settings.js:
--------------------------------------------------------------------------------
1 | frappe.require("assets/india_compliance/js/transaction.js", function () {
2 | frappe.ui.form.on("Document Naming Settings", {
3 | transaction_type(frm) {
4 | show_gst_invoice_no_banner(frm);
5 | },
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_credential/gst_credential.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class GSTCredential(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/rename_reverse_charge_to_purchase_reverse_charge.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_value(
6 | "GST Account",
7 | {"account_type": "Reverse Charge"},
8 | "account_type",
9 | "Purchase Reverse Charge",
10 | )
11 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/document_naming_rule.js:
--------------------------------------------------------------------------------
1 | frappe.require("assets/india_compliance/js/transaction.js", function () {
2 | frappe.ui.form.on("Document Naming Rule", {
3 | async document_type(frm) {
4 | await show_gst_invoice_no_banner(frm);
5 | },
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/bill_of_entry_item/bill_of_entry_item.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class BillofEntryItem(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/company_print_options/company_print_options.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class CompanyPrintOptions(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply_item/gst_inward_supply_item.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class GSTInwardSupplyItem(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/update_supplier_filing_status.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | GSTR2 = frappe.qb.DocType("GST Inward Supply")
6 | (
7 | frappe.qb.update(GSTR2)
8 | .set("is_supplier_return_filed", 1)
9 | .where(GSTR2.gstr_1_filled == 1)
10 | .run()
11 | )
12 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_state_name_to_puducherry.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_value(
6 | "Address",
7 | {"gst_state": "Pondicherry"},
8 | {
9 | "gst_state": "Puducherry",
10 | "state": "Puducherry",
11 | },
12 | )
13 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form_invoice_detail/c_form_invoice_detail.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 | # License: GNU General Public License v3. See license.txt
3 |
4 |
5 | from frappe.model.document import Document
6 |
7 |
8 | class CFormInvoiceDetail(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/__init__.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.utils.user import is_website_user
3 |
4 | __version__ = "16.0.0-dev"
5 |
6 |
7 | def check_app_permission():
8 | if frappe.session.user == "Administrator":
9 | return True
10 |
11 | if is_website_user():
12 | return False
13 |
14 | return True
15 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/customer.js:
--------------------------------------------------------------------------------
1 | const DOCTYPE = "Customer";
2 |
3 | validate_pan(DOCTYPE);
4 | validate_gstin(DOCTYPE);
5 | update_gstin_in_other_documents(DOCTYPE);
6 | show_overseas_disabled_warning(DOCTYPE);
7 | set_gstin_options_and_status(DOCTYPE);
8 | set_gst_category(DOCTYPE);
9 | set_pan_status(DOCTYPE);
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_default_gstr1_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_single_value(
6 | "GST Settings",
7 | {
8 | "enable_gstr_1_api": 1,
9 | "freeze_transactions": 1,
10 | "filing_frequency": "Monthly",
11 | },
12 | )
13 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore } from 'vuex'
2 | import authStore from "./modules/auth";
3 | import accountStore from "./modules/account";
4 |
5 | export default createStore({
6 | modules: {
7 | auth: authStore,
8 | account: accountStore,
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_applicable_company/e_invoice_applicable_company.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class eInvoiceApplicableCompany(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/config/docs.py:
--------------------------------------------------------------------------------
1 | """
2 | Configuration for docs
3 | """
4 |
5 | # source_link = "https://github.com/[org_name]/india_compliance"
6 | # headline = "App that does everything"
7 | # sub_heading = "Yes, you got that right the first time, everything"
8 |
9 |
10 | def get_context(context):
11 | context.brand_html = "India Compliance"
12 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/make_e_invoice_log_extensible.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | e_invoice_log = frappe.qb.DocType("e-Invoice Log")
6 |
7 | frappe.qb.update(e_invoice_log).set(
8 | e_invoice_log.reference_name, e_invoice_log.sales_invoice
9 | ).set(e_invoice_log.reference_doctype, "Sales Invoice").run()
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/remove_duplicate_web_template.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | template_name = "e-Invoice QR Code"
6 | if frappe.db.exists(
7 | "Web Template Field",
8 | {"parent": template_name, "fieldname": "e_invoice_qr_text"},
9 | ):
10 | frappe.db.delete("Web Template", template_name)
11 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/india_compliance_taxes_and_charges/india_compliance_taxes_and_charges.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class IndiaComplianceTaxesandCharges(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/update_action_for_gst_inward_supply.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | # Discard the action "Accept Supplier Values"
6 | frappe.db.set_value(
7 | "GST Inward Supply",
8 | {"action": ["in", ["Accept My Values", "Accept Supplier Values"]]},
9 | "action",
10 | "Accept",
11 | )
12 |
--------------------------------------------------------------------------------
/india_compliance/config/desktop.py:
--------------------------------------------------------------------------------
1 | from frappe import _
2 |
3 |
4 | def get_data():
5 | return [
6 | {
7 | "module_name": "India Compliance",
8 | "color": "grey",
9 | "icon": "octicon octicon-file-directory",
10 | "type": "module",
11 | "label": _("India Compliance"),
12 | }
13 | ]
14 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_tax_category_for_rcm.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | tax_category = frappe.qb.DocType("Tax Category")
6 |
7 | frappe.qb.update(tax_category).set(tax_category.is_reverse_charge, 1).where(
8 | tax_category.name.isin(("Reverse Charge Out-State", "Reverse Charge In-State"))
9 | ).run()
10 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form/test_c_form.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | import unittest
5 |
6 | # test_records = frappe.get_test_records('C-Form')
7 |
8 | IGNORE_TEST_RECORD_DEPENDENCIES = ["Company", "Customer", "Sales Invoice", "Territory"]
9 |
10 |
11 | class TestCForm(unittest.TestCase):
12 | pass
13 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/pan/pan.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("PAN", {
5 | refresh(frm) {
6 | frm.disable_form();
7 |
8 | frm.add_custom_button(__("Refresh PAN Status"), () => {
9 | frm.call("update_pan_status");
10 | });
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/remove_consumer_gst_category.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | for doctype in ("Customer", "Supplier", "Address"):
6 | if not frappe.db.has_column(doctype, "gst_category"):
7 | continue
8 |
9 | frappe.db.set_value(
10 | doctype, {"gst_category": "Consumer"}, "gst_category", "Unregistered"
11 | )
12 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/rename_gstr1_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.utils import sbool
3 |
4 |
5 | def execute():
6 | settings = frappe.get_cached_doc("GST Settings")
7 | if not sbool(settings.get("compare_gstr_1_data")):
8 | return
9 |
10 | frappe.db.set_single_value(
11 | "GST Settings", {"enable_gstr_1_api": 1, "compare_unfiled_data": 1}
12 | )
13 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/delete_purchase_receipt_standard_custom_fields.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | FIELDS = [
4 | "transporter_name",
5 | "lr_no",
6 | "lr_date",
7 | ]
8 |
9 |
10 | def execute():
11 | frappe.db.delete(
12 | "Custom Field",
13 | filters={
14 | "dt": "Purchase Receipt",
15 | "fieldname": ("in", FIELDS),
16 | },
17 | )
18 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/email_template.py:
--------------------------------------------------------------------------------
1 | from india_compliance.gst_india.setup import update_default_email_template
2 |
3 |
4 | def after_rename(doc, method=None, *args, **kwargs):
5 | old_name = args[0]
6 | new_name = args[1]
7 |
8 | update_default_email_template(old_name, new_name)
9 |
10 |
11 | def on_trash(doc, method=None):
12 | update_default_email_template(doc.name, None)
13 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_state_code_for_daman_and_diu.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | address = frappe.qb.DocType("Address")
6 |
7 | (
8 | frappe.qb.update(address)
9 | .set(address.gst_state, "Dadra and Nagar Haveli and Daman and Diu")
10 | .set(address.gst_state_number, "26")
11 | .where(address.gst_state == "Daman and Diu")
12 | ).run()
13 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_purchase_reco_email_template.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.setup import EMAIL_TEMPLATE_DATA
4 |
5 |
6 | def execute():
7 | doctype = EMAIL_TEMPLATE_DATA.pop("doctype")
8 | name = EMAIL_TEMPLATE_DATA.pop("name")
9 |
10 | if not frappe.db.exists(doctype, name):
11 | return
12 |
13 | frappe.db.set_value(doctype, name, EMAIL_TEMPLATE_DATA)
14 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/rename_import_of_capital_goods.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if "eligibility_for_itc" not in frappe.db.get_table_columns("Purchase Invoice"):
6 | return
7 |
8 | frappe.db.set_value(
9 | "Purchase Invoice",
10 | {"eligibility_for_itc": "Import Of Capital Goods"},
11 | "eligibility_for_itc",
12 | "Import Of Goods",
13 | )
14 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_gst_category.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | for doctype, field in (
6 | {
7 | "Sales Invoice": "billing_address_gstin",
8 | "Purchase Invoice": "supplier_gstin",
9 | }
10 | ).items():
11 | frappe.db.set_value(
12 | doctype, {field: ("in", (None, ""))}, "gst_category", "Unregistered"
13 | )
14 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_default_auto_reconciliation_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.set_single_value(
6 | "GST Settings",
7 | {
8 | "inward_supply_period": 2,
9 | "reconcile_on_tuesday": 1,
10 | "reconcile_on_friday": 1,
11 | "reconcile_for_b2b": 1,
12 | "reconcile_for_cdnr": 1,
13 | },
14 | )
15 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/expense_claim.js:
--------------------------------------------------------------------------------
1 | frappe.ui.form.on("Expense Claim", {
2 | company: set_gstin_options,
3 | });
4 |
5 | frappe.ui.form.on("Expense Taxes and Charges", {
6 | account_head: toggle_gstin_for_expense_claim,
7 | accounts_head_remove: toggle_gstin_for_expense_claim,
8 | });
9 |
10 | function toggle_gstin_for_expense_claim(frm) {
11 | toggle_company_gstin(frm, "taxes", "account_head");
12 | }
--------------------------------------------------------------------------------
/india_compliance/patches/v14/enable_sales_through_ecommerce_operator.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.patches.post_install.set_default_gst_settings import (
4 | enable_sales_through_ecommerce_operators,
5 | )
6 |
7 |
8 | def execute():
9 | new_settings = {}
10 |
11 | enable_sales_through_ecommerce_operators(new_settings)
12 |
13 | if new_settings:
14 | frappe.db.set_single_value("GST Settings", new_settings)
15 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/migrate_print_options_to_new_field.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.has_column("Company Print Options", "autofield"):
6 | return
7 |
8 | doc = frappe.qb.DocType("Company Print Options")
9 |
10 | (
11 | frappe.qb.update(doc)
12 | .set(doc.print_label, doc.autofield)
13 | .set(doc.print_value, doc.autofield_value)
14 | .run()
15 | )
16 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/setup.py:
--------------------------------------------------------------------------------
1 | from india_compliance.income_tax_india.constants.custom_fields import CUSTOM_FIELDS
2 | from india_compliance.utils.custom_fields import get_custom_fields_creator
3 |
4 | _create_custom_fields = get_custom_fields_creator("Income Tax India")
5 |
6 |
7 | def after_install():
8 | create_custom_fields()
9 |
10 |
11 | def create_custom_fields():
12 | _create_custom_fields(CUSTOM_FIELDS, ignore_validate=True)
13 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/page/india_compliance_account/india_compliance_account.js:
--------------------------------------------------------------------------------
1 | const PAGE_NAME = "india-compliance-account";
2 | let icAccountPage;
3 |
4 | frappe.pages[PAGE_NAME].on_page_load = async function (wrapper) {
5 | await frappe.require([
6 | "india_compliance_account.bundle.js",
7 | "india_compliance_account.bundle.css",
8 | ]);
9 |
10 | icAccountPage = new india_compliance.pages.IndiaComplianceAccountPage(wrapper, PAGE_NAME);
11 | };
12 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_autogenerate_e_waybill_with_e_invoice.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | settings = frappe.get_single("GST Settings")
6 |
7 | settings.db_set(
8 | "generate_e_waybill_with_e_invoice",
9 | (
10 | 0
11 | if (
12 | settings.auto_generate_e_invoice
13 | and not settings.auto_generate_e_waybill
14 | )
15 | else 1
16 | ),
17 | )
18 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_tax_withholding_categories.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.income_tax_india.overrides.company import (
4 | create_or_update_tax_withholding_category,
5 | )
6 |
7 |
8 | def execute():
9 | company_list = frappe.get_all(
10 | "Company", filters={"country": "India"}, pluck="name", order_by="lft asc"
11 | )
12 |
13 | for company in company_list:
14 | create_or_update_tax_withholding_category(company)
15 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/stop_unnecessary_scheduled_jobs.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | settings = frappe.get_single("GST Settings")
6 |
7 | frappe.db.set_value(
8 | "Scheduled Job Type",
9 | {
10 | "method": "india_compliance.gst_india.doctype.purchase_reconciliation_tool.purchase_reconciliation_tool.auto_refresh_authtoken"
11 | },
12 | "stopped",
13 | not settings.enable_auto_reconciliation,
14 | )
15 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/remove_itc_amount_custom_fields.py:
--------------------------------------------------------------------------------
1 | from india_compliance.utils.custom_fields import delete_old_fields
2 |
3 |
4 | def execute():
5 | # these fields are not required
6 | fields_to_delete = [
7 | "gst_col_break",
8 | "itc_integrated_tax",
9 | "itc_central_tax",
10 | "itc_state_tax",
11 | "itc_cess_amount",
12 | ]
13 |
14 | for field in fields_to_delete:
15 | delete_old_fields(field, "Purchase Invoice")
16 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/multiple_pi_in_boe.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | boe = frappe.qb.DocType("Bill of Entry", alias="boe")
6 | boe_item = frappe.qb.DocType("Bill of Entry Item", alias="boe_item")
7 |
8 | # link BOE Item to it's purchase invoice
9 | (
10 | frappe.qb.update(boe_item)
11 | .join(boe)
12 | .on(boe_item.parent == boe.name)
13 | .set(boe_item.purchase_invoice, boe.purchase_invoice)
14 | .run(as_dict=True)
15 | )
16 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance.bundle.js:
--------------------------------------------------------------------------------
1 | import "./utils";
2 | import "./gst_api_handler";
3 | import "./quick_entry";
4 | import "./transaction";
5 | import "./audit_trail_notification";
6 | import "./item_tax_template_notification";
7 | import "./new_gst_category_notification";
8 | import "./quick_info_popover";
9 | import "./custom_number_card";
10 | import "./taxes_controller";
11 | import "./help_links";
12 | import "./reconciliation_components/tabs";
13 | import "./components/set_gstin_options";
14 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/PageTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ title }}
4 |
5 |
6 |
7 |
12 |
13 |
26 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_payment_entry_fields.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.utils.custom_fields import delete_old_fields
4 |
5 |
6 | def execute():
7 | if not frappe.db.has_column("Payment Entry", "customer_gstin"):
8 | return
9 |
10 | payment_entry = frappe.qb.DocType("Payment Entry")
11 | frappe.qb.update(payment_entry).set(
12 | payment_entry.billing_address_gstin, payment_entry.customer_gstin
13 | ).run()
14 |
15 | delete_old_fields("customer_gstin", "Payment Entry")
16 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/data/address_template.html:
--------------------------------------------------------------------------------
1 | {{ address_line1 }} {% if address_line2 %}{{ address_line2 }} {% endif -%}{{ city }}
2 | {% if gst_state %}{{ gst_state }}{% endif -%}
3 | {% if gst_state_number %}, State Code: {{ gst_state_number }} {% endif -%}
4 | {% if pincode %}PIN Code: {{ pincode }} {% endif -%}
5 | {{ country }}
6 | {% if phone %}Phone: {{ phone }} {% endif -%}
7 | {% if fax %}Fax: {{ fax }} {% endif -%}
8 | {% if email_id %}Email: {{ email_id }} {% endif -%}
9 | {% if gstin %}GSTIN: {{ gstin }} {% endif -%}
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_reverse_charge_applicability_in_supplier.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | reverse_charge_tax_category = frappe.db.get_all(
6 | "Tax Category",
7 | filters={"is_reverse_charge": "1"},
8 | pluck="name",
9 | )
10 |
11 | if not reverse_charge_tax_category:
12 | return
13 |
14 | frappe.db.set_value(
15 | "Supplier",
16 | {"tax_category": ("in", reverse_charge_tax_category)},
17 | "is_reverse_charge_applicable",
18 | 1,
19 | )
20 |
--------------------------------------------------------------------------------
/india_compliance/public/js/custom_number_card.js:
--------------------------------------------------------------------------------
1 | let FrappeNumberCard = frappe.widget.widget_factory.number_card;
2 |
3 | class CustomNumberCard extends FrappeNumberCard {
4 | render_number() {
5 | if (
6 | [
7 | "Pending e-Waybill",
8 | "Pending e-Invoices",
9 | "Invoice Cancelled But Not e-Invoice",
10 | ].includes(this.card_doc.name) &&
11 | !this.formatted_number
12 | )
13 | this.card_doc.color = null;
14 |
15 | super.render_number();
16 | }
17 | }
18 |
19 | frappe.widget.widget_factory.number_card = CustomNumberCard;
20 |
--------------------------------------------------------------------------------
/.github/helper/site_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "db_host": "127.0.0.1",
3 | "db_port": 3306,
4 | "db_name": "test_frappe",
5 | "db_password": "test_frappe",
6 | "db_type": "mariadb",
7 | "auto_email_id": "test@example.com",
8 | "mail_server": "smtp.example.com",
9 | "mail_login": "test@example.com",
10 | "mail_password": "test",
11 | "admin_password": "admin",
12 | "root_login": "root",
13 | "root_password": "travis",
14 | "host_name": "http://test_site:8000",
15 | "install_apps": ["erpnext"],
16 | "ic_api_secret": "*****",
17 | "throttle_user_limit": 100
18 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstin/gstin.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("GSTIN", {
5 | refresh(frm) {
6 | frm.disable_form();
7 |
8 | frm.add_custom_button(__("Refresh GSTIN Status"), () => {
9 | frm.call("update_gstin_status");
10 | });
11 |
12 | frm.add_custom_button(__("Refresh Transporter ID Status"), () => {
13 | frm.call("update_transporter_id_status");
14 | });
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/upi_qr_code/upi_qr_code.json:
--------------------------------------------------------------------------------
1 | {
2 | "creation": "2024-05-03 10:34:51.575300",
3 | "docstatus": 0,
4 | "doctype": "Web Template",
5 | "fields": [
6 | {
7 | "fieldname": "upi_qr_text",
8 | "fieldtype": "Text",
9 | "label": "UPI QR Code",
10 | "reqd": 0
11 | }
12 | ],
13 | "idx": 0,
14 | "modified": "2024-06-03 13:19:22.517387",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "UPI QR Code",
18 | "owner": "Administrator",
19 | "standard": 1,
20 | "template": "",
21 | "type": "Component"
22 | }
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/pages/PageNotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
404
4 | Page Not Found
5 |
6 | Go to Home
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/web_template/e_invoice_qr/e_invoice_qr.json:
--------------------------------------------------------------------------------
1 | {
2 | "creation": "2024-06-27 12:22:43.643151",
3 | "docstatus": 0,
4 | "doctype": "Web Template",
5 | "fields": [
6 | {
7 | "fieldname": "e_invoice_qr_text",
8 | "fieldtype": "Text",
9 | "label": "QR Text",
10 | "reqd": 0
11 | }
12 | ],
13 | "idx": 0,
14 | "modified": "2024-07-01 11:39:21.368461",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "e-Invoice QR",
18 | "owner": "Administrator",
19 | "standard": 1,
20 | "template": "",
21 | "type": "Component"
22 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_3b_report/gstr_3b_report_list.js:
--------------------------------------------------------------------------------
1 | frappe.listview_settings["GSTR 3B Report"] = {
2 | hide_name_column: true,
3 | add_fields: ["generation_status"],
4 | get_indicator: function (doc) {
5 | var colors = {
6 | "In Process": "orange",
7 | Generated: "green",
8 | Failed: "red",
9 | };
10 | return [
11 | __(doc.generation_status),
12 | colors[doc.generation_status],
13 | "generation_status,=," + doc.generation_status,
14 | ];
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_enable_retry_einv_ewb_generation.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | frappe.db.sql(
6 | """
7 | UPDATE `tabSingles` AS t1
8 | SET `value` = (
9 | SELECT IFNULL(
10 | (SELECT `value` FROM `tabSingles` AS t2
11 | WHERE t2.`doctype` = 'GST Settings'
12 | AND t2.`field` = 'enable_retry_e_invoice_generation'), 0)
13 | )
14 | WHERE t1.`doctype` = 'GST Settings'
15 | AND t1.`field` = 'enable_retry_einv_ewb_generation'
16 | """
17 | )
18 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/utils.js:
--------------------------------------------------------------------------------
1 | function fetch_gstins(report) {
2 | const company = report.get_filter_value('company');
3 | const gstin_field = report.get_filter('company_gstin');
4 |
5 | if (!company) {
6 | gstin_field.df.options = [""];
7 | gstin_field.refresh();
8 | return;
9 | }
10 |
11 | frappe.call({
12 | method:'india_compliance.gst_india.utils.get_gstin_list',
13 | async: false,
14 | args: {
15 | party: company
16 | },
17 | callback(r) {
18 | r.message.unshift("");
19 | gstin_field.df.options = r.message;
20 | gstin_field.refresh();
21 | }
22 | });
23 | }
24 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/overrides/tax_withholding_category.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def on_change(doc, method=None):
5 | frappe.cache.delete_value("tax_withholding_accounts")
6 |
7 |
8 | def get_tax_withholding_accounts(company):
9 | def _get_tax_withholding_accounts():
10 | return set(
11 | frappe.get_all(
12 | "Tax Withholding Account", pluck="account", filters={"company": company}
13 | )
14 | )
15 |
16 | return frappe.cache.hget(
17 | "tax_withholding_accounts", company, generator=_get_tax_withholding_accounts
18 | )
19 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/PreLoader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
India Compliance
4 | by Resilient Tech
5 |
6 |
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_item_details_from_purchase_invoice_to_bill_of_entry.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | boe_item = frappe.qb.DocType("Bill of Entry Item", alias="boe_item")
6 | pi_item = frappe.qb.DocType("Purchase Invoice Item")
7 |
8 | (
9 | frappe.qb.update(boe_item)
10 | .left_join(pi_item)
11 | .on(pi_item.name == boe_item.pi_detail)
12 | .set(boe_item.gst_hsn_code, pi_item.gst_hsn_code)
13 | .set(boe_item.qty, pi_item.qty)
14 | .set(boe_item.uom, pi_item.uom)
15 | .where(boe_item.docstatus == 1)
16 | .run()
17 | )
18 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/test_setup_wizard.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.tests import IntegrationTestCase
3 |
4 |
5 | class TestSetupWizard(IntegrationTestCase):
6 | def test_setup_wizard_with_valid_gstin(self):
7 | setup_company = "Wind Power LLP"
8 | company = frappe.get_doc("Company", setup_company)
9 |
10 | self.assertDocumentEqual(
11 | {"gst_category": "Unregistered", "gstin": None, "default_gst_rate": "18.0"},
12 | company,
13 | )
14 |
15 | self.assertEqual(
16 | frappe.db.get_single_value("Accounts Settings", "enable_audit_trail"), 0
17 | )
18 |
--------------------------------------------------------------------------------
/india_compliance/income_tax_india/constants/__init__.py:
--------------------------------------------------------------------------------
1 | TDS_SECTIONS = [
2 | "193",
3 | "194",
4 | "194BB",
5 | "194EE",
6 | "194A",
7 | "194B",
8 | "194C",
9 | "194D",
10 | "194F",
11 | "194G",
12 | "194H",
13 | "194I",
14 | "194JA",
15 | "194JB",
16 | "194LA",
17 | "194I(a)",
18 | "194I(b)",
19 | "194LBA",
20 | "194DA",
21 | "192A",
22 | "192B",
23 | "194LBB",
24 | "194IA",
25 | "194N",
26 | "194Q",
27 | "194T",
28 | "195",
29 | "206C(1H)",
30 | ]
31 |
32 | TDS_ENTITY_TYPE = ["Individual", "Company", "Company Assessee", "No PAN / Invalid PAN"]
33 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include MANIFEST.in
2 | include requirements.txt
3 | include *.json
4 | include *.md
5 | include *.py
6 | include *.txt
7 | recursive-include india_compliance *.css
8 | recursive-include india_compliance *.csv
9 | recursive-include india_compliance *.html
10 | recursive-include india_compliance *.ico
11 | recursive-include india_compliance *.js
12 | recursive-include india_compliance *.json
13 | recursive-include india_compliance *.md
14 | recursive-include india_compliance *.png
15 | recursive-include india_compliance *.py
16 | recursive-include india_compliance *.svg
17 | recursive-include india_compliance *.txt
18 | recursive-exclude india_compliance *.pyc
--------------------------------------------------------------------------------
/india_compliance/gst_india/page/india_compliance_account/india_compliance_account.json:
--------------------------------------------------------------------------------
1 | {
2 | "content": null,
3 | "creation": "2022-02-25 13:28:27.343408",
4 | "docstatus": 0,
5 | "doctype": "Page",
6 | "idx": 0,
7 | "modified": "2022-08-03 20:09:15.429993",
8 | "modified_by": "Administrator",
9 | "module": "GST India",
10 | "name": "india-compliance-account",
11 | "owner": "Administrator",
12 | "page_name": "india-compliance-account",
13 | "restrict_to_domain": "",
14 | "roles": [
15 | {
16 | "role": "System Manager"
17 | }
18 | ],
19 | "script": null,
20 | "standard": "Yes",
21 | "style": null,
22 | "system_page": 0,
23 | "title": "India Compliance Account"
24 | }
--------------------------------------------------------------------------------
/india_compliance/patches/v14/unset_inward_supply_link_for_cancelled_purchase.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | DOCTYPES = ("Purchase Invoice", "Bill of Entry")
4 |
5 |
6 | def execute():
7 | for doctype in DOCTYPES:
8 | cancelled_doc = get_cancelled_doc(doctype)
9 | frappe.db.set_value(
10 | "GST Inward Supply",
11 | {"link_name": ("in", cancelled_doc), "link_doctype": doctype},
12 | {"link_name": "", "link_doctype": "", "match_status": ""},
13 | )
14 |
15 |
16 | def get_cancelled_doc(doctype):
17 | return frappe.get_all(
18 | doctype,
19 | filters={"docstatus": 2},
20 | pluck="name",
21 | )
22 |
--------------------------------------------------------------------------------
/.github/workflows/docs-required.yml:
--------------------------------------------------------------------------------
1 | name: Documentation Required
2 |
3 | on:
4 | pull_request:
5 | types: [ opened, synchronize, reopened, edited ]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 10
11 |
12 | steps:
13 | - name: 'Setup Environment'
14 | uses: actions/setup-python@v6
15 | with:
16 | python-version: '3.11'
17 | - uses: actions/checkout@v6
18 |
19 | - name: Validate Docs
20 | env:
21 | PR_NUMBER: ${{ github.event.number }}
22 | run: |
23 | pip install requests --quiet
24 | python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
25 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/set_default_for_new_gst_category_notification.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | import frappe.defaults
3 | from frappe.utils.user import get_users_with_role
4 |
5 |
6 | def execute():
7 | if not frappe.db.exists("Company", {"country": "India"}):
8 | return
9 |
10 | # Users affected by creation of new GST category
11 | if not frappe.db.exists(
12 | "Purchase Invoice", {"itc_classification": "Input Service Distributor"}
13 | ):
14 | return
15 |
16 | for user in get_users_with_role("Accounts Manager"):
17 | frappe.defaults.set_user_default(
18 | "needs_new_gst_category_notification", 1, user=user
19 | )
20 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/remove_ignore_reconciliation_field.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.utils.custom_fields import delete_old_fields
4 |
5 | DOCTYPES = ("Purchase Invoice", "Bill of Entry")
6 |
7 |
8 | def execute():
9 | fieldname = "ignore_reconciliation"
10 |
11 | for doctype in DOCTYPES:
12 | if fieldname not in frappe.db.get_table_columns(doctype):
13 | continue
14 |
15 | frappe.db.set_value(doctype, {fieldname: 1}, "reconciliation_status", "Ignored")
16 | frappe.db.sql_ddl(
17 | "alter table `tab{0}` drop column {1}".format(doctype, fieldname)
18 | )
19 |
20 | delete_old_fields(fieldname, DOCTYPES)
21 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_e_invoice_status.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull
3 |
4 | from india_compliance.gst_india.doctype.gst_settings.gst_settings import (
5 | update_e_invoice_status,
6 | )
7 |
8 |
9 | def execute():
10 | update_e_invoice_status()
11 | set_pending_cancellation_status()
12 |
13 |
14 | def set_pending_cancellation_status():
15 | sales_invoice = frappe.qb.DocType("Sales Invoice")
16 |
17 | (
18 | frappe.qb.update(sales_invoice)
19 | .set("einvoice_status", "Pending Cancellation")
20 | .where((sales_invoice.docstatus == 2) & (IfNull(sales_invoice.irn, "") != ""))
21 | .run()
22 | )
23 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/migrate_gstr1_log_to_returns_log.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.table_exists("GSTR-1 Log"):
6 | return
7 |
8 | old = frappe.qb.DocType("GSTR-1 Log")
9 | old_docs = frappe.qb.from_(old).select("*").run(as_dict=True)
10 |
11 | for doc in old_docs:
12 | new_doc = frappe.get_doc(
13 | {**doc, "doctype": "GST Return Log", "name": None, "return_type": "GSTR1"}
14 | )
15 | new_doc.insert(ignore_if_duplicate=True)
16 |
17 | # Drop the old table
18 | frappe.db.delete("GSTR-1 Log")
19 |
20 | # Clear all fields saved in GSTR-1
21 | frappe.db.delete("Singles", {"doctype": "GSTR-1"})
22 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/report/audit_trail/audit_trail.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 0,
3 | "columns": [],
4 | "creation": "2023-07-14 18:21:29.788627",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "modified": "2023-07-25 16:35:23.470355",
12 | "modified_by": "Administrator",
13 | "module": "Audit Trail",
14 | "name": "Audit Trail",
15 | "owner": "Administrator",
16 | "prepared_report": 0,
17 | "ref_doctype": "Version",
18 | "report_name": "Audit Trail",
19 | "report_type": "Script Report",
20 | "roles": [
21 | {
22 | "role": "System Manager"
23 | },
24 | {
25 | "role": "Administrator"
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parserPreset: "conventional-changelog-conventionalcommits",
3 | rules: {
4 | "subject-empty": [2, "never"],
5 | "type-case": [2, "always", "lower-case"],
6 | "type-empty": [2, "never"],
7 | "type-enum": [
8 | 2,
9 | "always",
10 | [
11 | "build",
12 | "chore",
13 | "ci",
14 | "docs",
15 | "feat",
16 | "fix",
17 | "perf",
18 | "refactor",
19 | "revert",
20 | "style",
21 | "test",
22 | ],
23 | ],
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | require_ci_to_pass: true
3 |
4 | comment:
5 | behavior: default
6 | layout: reach,diff,flags,tree,reach
7 | show_carryforward_flags: false
8 |
9 | coverage:
10 | precision: 2
11 | round: down
12 | status:
13 | changes: false
14 | default_rules:
15 | flag_coverage_not_uploaded_behavior: include
16 |
17 | patch:
18 | default:
19 | base: auto
20 | branches:
21 | - ^develop$
22 | if_ci_failed: ignore
23 | only_pulls: true
24 | target: 85%
25 | threshold: 1%
26 |
27 | project:
28 | default:
29 | base: auto
30 | threshold: 20%
31 |
32 | github_checks:
33 | annotations: true
34 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/add_match_found_in_purchase_reconciliation_status.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | DOCTYPES = ("Purchase Invoice", "Bill of Entry")
4 |
5 |
6 | def execute():
7 | for doctype in DOCTYPES:
8 | doc_names = frappe.get_all(
9 | "GST Inward Supply",
10 | filters={
11 | "action": "No Action",
12 | "link_name": ("!=", ""),
13 | "link_doctype": doctype,
14 | },
15 | pluck="link_name",
16 | )
17 |
18 | if not doc_names:
19 | continue
20 |
21 | frappe.db.set_value(
22 | doctype, {"name": ("in", doc_names)}, "reconciliation_status", "Match Found"
23 | )
24 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/remove_deprecated_docs.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | to_delete = {
6 | "DocType": [
7 | "E Invoice Request Log",
8 | "E Invoice Settings",
9 | "E Invoice User",
10 | "HSN Tax Rate",
11 | ],
12 | "Print Format": [
13 | "GST E-Invoice",
14 | ],
15 | "Report": [
16 | "Eway Bill",
17 | ],
18 | }
19 |
20 | for doctype, names in to_delete.items():
21 | frappe.delete_doc(
22 | doctype,
23 | names,
24 | force=True,
25 | ignore_permissions=True,
26 | ignore_missing=True,
27 | )
28 |
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "branches": ["version-14", "version-15"],
3 | "plugins": [
4 | "@semantic-release/commit-analyzer", {
5 | "preset": "angular",
6 | "releaseRules": [
7 | {"breaking": true, "release": false}
8 | ]
9 | },
10 | "@semantic-release/release-notes-generator",
11 | [
12 | "@semantic-release/exec", {
13 | "prepareCmd": 'sed -ir -E "s/\"[0-9]+\.[0-9]+\.[0-9]+\"/\"${nextRelease.version}\"/" india_compliance/__init__.py'
14 | }
15 | ],
16 | [
17 | "@semantic-release/git", {
18 | "assets": ["india_compliance/__init__.py"],
19 | "message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}"
20 | }
21 | ],
22 | "@semantic-release/github"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/item.js:
--------------------------------------------------------------------------------
1 | frappe.ui.form.on('Item', {
2 | onload: function(frm) {
3 | india_compliance.set_hsn_code_query(frm.get_field("gst_hsn_code"));
4 | },
5 |
6 | gst_hsn_code: function(frm) {
7 | if ((!frm.doc.taxes || !frm.doc.taxes.length) && frm.doc.gst_hsn_code) {
8 | frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
9 | $.each(hsn_doc.taxes || [], function(_, tax) {
10 | let a = frappe.model.add_child(frm.doc, 'Item Tax', 'taxes');
11 | a.item_tax_template = tax.item_tax_template;
12 | a.tax_category = tax.tax_category;
13 | a.valid_from = tax.valid_from;
14 | frm.refresh_field('taxes');
15 | });
16 | });
17 | }
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/india_compliance/public/js/components/set_gstin_options.js:
--------------------------------------------------------------------------------
1 | frappe.provide("india_compliance");
2 |
3 | india_compliance.set_gstin_options = async function (
4 | frm,
5 | show_all_option = false,
6 | exclude_isd = false
7 | ) {
8 | const { query, params } = india_compliance.get_gstin_query(
9 | frm.doc.company,
10 | "Company",
11 | exclude_isd
12 | );
13 | const { message } = await frappe.call({
14 | method: query,
15 | args: params,
16 | });
17 |
18 | if (!message) return [];
19 | if (show_all_option) message.unshift("All");
20 |
21 | const gstin_field = frm.get_field("company_gstin");
22 | gstin_field.set_data(message);
23 | return message;
24 | };
25 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/Message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ×
6 |
7 |
8 |
9 |
10 |
27 |
28 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/set_download_document_for_2a_2b.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if frappe.db.has_column("GST Inward Supply", "is_downloaded_from_2a"):
6 | # set "is_downloaded_from_2a" to "1" for all GST Inward Supply
7 | frappe.db.set_value(
8 | "GST Inward Supply", {"name": ["is", "set"]}, "is_downloaded_from_2a", 1
9 | )
10 |
11 | if frappe.db.has_column("GST Inward Supply", "is_downloaded_from_2b"):
12 | # set "is_downloaded_from_2b" to "1" where 2B return period is set
13 | frappe.db.set_value(
14 | "GST Inward Supply",
15 | {"return_period_2b": ["is", "set"]},
16 | "is_downloaded_from_2b",
17 | 1,
18 | )
19 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/update_action_for_rejected_invoices_in_gst_inward_supply.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull
3 |
4 |
5 | def execute():
6 | """
7 | Update the action for invoices where ims_action is "Rejected"
8 | 1. If invoice is "Rejected" then mark action as "Ignore" only if invoice is not matched.
9 | 2. And copy current action to previous action.
10 | """
11 | GSTR2 = frappe.qb.DocType("GST Inward Supply")
12 |
13 | (
14 | frappe.qb.update(GSTR2)
15 | .set("previous_action", GSTR2.action)
16 | .set("action", "Ignore")
17 | .where(GSTR2.ims_action == "Rejected")
18 | .where(IfNull(GSTR2.link_name, "") == "")
19 | .run()
20 | )
21 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_invoice/e_invoice.css:
--------------------------------------------------------------------------------
1 | .print-format .section-heading {
2 | margin-top: 15px;
3 | margin-bottom: 10px;
4 | font-weight: bold;
5 | }
6 |
7 |
8 | .print-format .print-heading span.docname {
9 | font-size: 15px;
10 | color: inherit;
11 | }
12 |
13 | .print-format .info-section {
14 | border-bottom: 1px solid #d1d8dd;
15 | padding-bottom: 16px;
16 | }
17 |
18 | .print-format h6.address-heading {
19 | font-weight: bold;
20 | margin-top: 8px;
21 | margin-bottom: 8px;
22 | }
23 |
24 | .print-format .e-invoice-table {
25 | margin: 10px 0;
26 | }
27 |
28 | .print-format .qrcode {
29 | width: 175px;
30 | }
31 |
32 | .print-format .no-preview-available {
33 | color: var(--gray-500);
34 | font-size: 14px;
35 | }
36 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_balance/gst_balance.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2023-06-05 14:48:26.693826",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "modified": "2023-06-05 14:48:26.693826",
12 | "modified_by": "Administrator",
13 | "module": "GST India",
14 | "name": "GST Balance",
15 | "owner": "Administrator",
16 | "prepared_report": 0,
17 | "ref_doctype": "GL Entry",
18 | "report_name": "GST Balance",
19 | "report_type": "Script Report",
20 | "roles": [
21 | {
22 | "role": "Accounts User"
23 | },
24 | {
25 | "role": "Accounts Manager"
26 | },
27 | {
28 | "role": "Auditor"
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_default_for_audit_trail_notification.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | import frappe.defaults
3 | from frappe.utils.user import get_users_with_role
4 |
5 |
6 | def execute():
7 | # All companies in India where PAN is of a registered company or is not set
8 | notification_required = frappe.get_all(
9 | "Company",
10 | filters={"country": "India"},
11 | or_filters=(
12 | ("pan", "like", "___C%"),
13 | ("pan", "is", "not set"),
14 | ),
15 | limit=1,
16 | )
17 |
18 | if not notification_required:
19 | return
20 |
21 | for user in get_users_with_role("Accounts Manager"):
22 | frappe.defaults.set_user_default("needs_audit_trail_notification", 1, user=user)
23 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_sales_register/gst_sales_register.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2024-03-11 16:02:41.778873",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "letterhead": null,
12 | "modified": "2024-03-11 16:03:18.740603",
13 | "modified_by": "Administrator",
14 | "module": "GST India",
15 | "name": "GST Sales Register",
16 | "owner": "Administrator",
17 | "prepared_report": 0,
18 | "ref_doctype": "Sales Invoice",
19 | "report_name": "GST Sales Register",
20 | "report_type": "Script Report",
21 | "roles": [
22 | {
23 | "role": "Accounts Manager"
24 | },
25 | {
26 | "role": "Accounts User"
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/india_compliance_api_usage/india_compliance_api_usage.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 0,
3 | "columns": [],
4 | "creation": "2025-02-11 12:15:09.380757",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "letterhead": null,
12 | "modified": "2025-02-11 12:17:30.611180",
13 | "modified_by": "Administrator",
14 | "module": "GST India",
15 | "name": "India Compliance API Usage",
16 | "owner": "Administrator",
17 | "prepared_report": 0,
18 | "ref_doctype": "Integration Request",
19 | "report_name": "India Compliance API Usage",
20 | "report_type": "Script Report",
21 | "roles": [
22 | {
23 | "role": "System Manager"
24 | }
25 | ],
26 | "timeout": 0
27 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_advance_detail/gst_advance_detail.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2023-09-17 16:44:05.262440",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "json": "{}",
12 | "letterhead": null,
13 | "modified": "2023-09-17 16:44:32.575646",
14 | "modified_by": "Administrator",
15 | "module": "GST India",
16 | "name": "GST Advance Detail",
17 | "owner": "Administrator",
18 | "prepared_report": 0,
19 | "ref_doctype": "Payment Entry",
20 | "report_name": "GST Advance Detail",
21 | "report_type": "Script Report",
22 | "roles": [
23 | {
24 | "role": "Accounts User"
25 | },
26 | {
27 | "role": "Accounts Manager"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/india_compliance/audit_trail/client_scripts/customize_form.js:
--------------------------------------------------------------------------------
1 | frappe.ui.form.on("Customize Form", {
2 | refresh: function (frm) {
3 | const audit_trail_enabled =
4 | frm.doc.doc_type && frm.doc.__onload?.audit_trail_enabled;
5 |
6 | // this should never happen, but just in case
7 | if (audit_trail_enabled && !frm.doc.track_changes) {
8 | frm.set_value("track_changes", 1);
9 | }
10 |
11 | frm.set_df_property("track_changes", "read_only", audit_trail_enabled);
12 | frm.set_df_property(
13 | "track_changes",
14 | "description",
15 | audit_trail_enabled
16 | ? __("This setting cannot be edited to ensure Audit Trail integrity.")
17 | : ""
18 | );
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/e_invoice_summary/e_invoice_summary.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 0,
3 | "columns": [],
4 | "creation": "2021-03-12 11:23:37.312294",
5 | "disable_prepared_report": 0,
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "json": "{}",
13 | "letter_head": "",
14 | "modified": "2022-03-01 15:49:13.912294",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "e-Invoice Summary",
18 | "owner": "Administrator",
19 | "prepared_report": 0,
20 | "ref_doctype": "Sales Invoice",
21 | "report_name": "e-Invoice Summary",
22 | "report_type": "Script Report",
23 | "roles": [
24 | {
25 | "role": "Accounts Manager"
26 | },
27 | {
28 | "role": "Accounts User"
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/subcontracting_order.js:
--------------------------------------------------------------------------------
1 | frappe.ui.form.on("Subcontracting Order", {
2 | setup(frm) {
3 | frm.set_query("taxes_and_charges", function () {
4 | return {
5 | filters: [
6 | ["disabled", "=", 0],
7 | ["company", "=", frm.doc.company],
8 | ],
9 | };
10 | });
11 | },
12 | onload(frm) {
13 | frm.taxes_controller = new india_compliance.taxes_controller(frm, {
14 | total_taxable_value: "total",
15 | });
16 | },
17 |
18 | taxes_and_charges(frm) {
19 | frm.taxes_controller.update_taxes(frm);
20 | },
21 | });
22 |
23 | frappe.ui.form.on(
24 | "Subcontracting Order Item",
25 | india_compliance.taxes_controller_events
26 | );
27 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/update_total_taxes_for_gst_inward_supply.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import Sum
3 |
4 |
5 | def execute():
6 | # Get GST Inward Supply Items
7 | dt = frappe.qb.DocType("GST Inward Supply Item")
8 | inward_supply_values = (
9 | frappe.qb.from_(dt)
10 | .select(
11 | dt.parent.as_("name"),
12 | Sum(dt.taxable_value).as_("taxable_value"),
13 | Sum(dt.igst).as_("igst"),
14 | Sum(dt.cgst).as_("cgst"),
15 | Sum(dt.sgst).as_("sgst"),
16 | Sum(dt.cess).as_("cess"),
17 | )
18 | .groupby(dt.parent)
19 | .run(as_dict=True)
20 | )
21 |
22 | frappe.db.bulk_update(
23 | "GST Inward Supply", {d.pop("name"): d for d in inward_supply_values}
24 | )
25 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gstin_status/gstin_status.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 0,
3 | "columns": [],
4 | "creation": "2025-01-28 17:10:48.875369",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "json": "{}",
12 | "letterhead": null,
13 | "modified": "2025-01-29 13:02:30.885362",
14 | "modified_by": "Administrator",
15 | "module": "GST India",
16 | "name": "GSTIN Status",
17 | "owner": "Administrator",
18 | "prepared_report": 0,
19 | "ref_doctype": "GSTIN",
20 | "report_name": "GSTIN Status",
21 | "report_type": "Script Report",
22 | "roles": [
23 | {
24 | "role": "System Manager"
25 | },
26 | {
27 | "role": "Accounts Manager"
28 | },
29 | {
30 | "role": "Accounts User"
31 | }
32 | ],
33 | "timeout": 1500
34 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gstr_3b_details/gstr_3b_details.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2023-07-17 17:06:02.333972",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "letter_head": "SMC - New",
12 | "letterhead": null,
13 | "modified": "2023-07-17 17:06:02.333972",
14 | "modified_by": "Administrator",
15 | "module": "GST India",
16 | "name": "GSTR-3B Details",
17 | "owner": "Administrator",
18 | "prepared_report": 0,
19 | "ref_doctype": "Purchase Invoice",
20 | "report_name": "GSTR-3B Details",
21 | "report_type": "Script Report",
22 | "roles": [
23 | {
24 | "role": "Accounts User"
25 | },
26 | {
27 | "role": "Accounts Manager"
28 | },
29 | {
30 | "role": "Auditor"
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_log/e_invoice_log_list.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.listview_settings["e-Invoice Log"] = {
5 | hide_name_column: true,
6 |
7 | button: {
8 | show: function (doc) {
9 | return doc.reference_name;
10 | },
11 |
12 | get_label: function () {
13 | return __("Open Reference");
14 | },
15 |
16 | get_description: function (doc) {
17 | return __("Open {0}", [
18 | `${__(doc.reference_doctype)}: ${doc.reference_name}`,
19 | ]);
20 | },
21 |
22 | action: function (doc) {
23 | frappe.set_route("Form", doc.reference_doctype, doc.reference_name);
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_waybill_log/e_waybill_log_list.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.listview_settings["e-Waybill Log"] = {
5 | hide_name_column: true,
6 |
7 | button: {
8 | show: function (doc) {
9 | return doc.reference_name;
10 | },
11 |
12 | get_label: function () {
13 | return __("Open Reference");
14 | },
15 |
16 | get_description: function (doc) {
17 | return __("Open {0}", [
18 | `${__(doc.reference_doctype)}: ${doc.reference_name}`,
19 | ]);
20 | },
21 |
22 | action: function (doc) {
23 | frappe.set_route("Form", doc.reference_doctype, doc.reference_name);
24 | },
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_action/gstr_action.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class GSTRAction(Document):
9 | pass
10 |
11 |
12 | def set_gstr_actions(doc, request_type, token, request_id, status=None):
13 | if not token:
14 | return
15 |
16 | row = {
17 | "request_type": request_type,
18 | "request_id": request_id,
19 | "token": token,
20 | "creation_time": frappe.utils.now_datetime(),
21 | }
22 |
23 | if status:
24 | row["status"] = status
25 |
26 | doc.append("actions", row)
27 | # Integration Requests may be cleared by a scheduler job
28 | doc.flags.ignore_links = True
29 | doc.save()
30 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/supplier.js:
--------------------------------------------------------------------------------
1 | const DOCTYPE = "Supplier";
2 |
3 | validate_pan(DOCTYPE);
4 | validate_gstin(DOCTYPE);
5 | update_gstin_in_other_documents(DOCTYPE);
6 | show_overseas_disabled_warning(DOCTYPE);
7 | set_gstin_options_and_status(DOCTYPE);
8 | set_gst_category(DOCTYPE);
9 | set_pan_status(DOCTYPE)
10 |
11 | frappe.ui.form.on(DOCTYPE, {
12 | gstin(frm) {
13 | if (
14 | !frm.doc.is_transporter ||
15 | !frm.doc.gstin ||
16 | frm.doc.gstin.length < 15 ||
17 | frm.doc.gst_transporter_id
18 | )
19 | return;
20 |
21 | frm.set_value("gst_transporter_id", frm.doc.gstin);
22 | },
23 |
24 | gst_transporter_id(frm) {
25 | india_compliance.validate_gst_transporter_id(frm.doc.gst_transporter_id, frm.doc);
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2018-04-26 10:49:29.159400",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "modified": "2023-05-08 18:32:52.251457",
12 | "modified_by": "Administrator",
13 | "module": "GST India",
14 | "name": "HSN-wise-summary of outward supplies",
15 | "owner": "Administrator",
16 | "prepared_report": 0,
17 | "ref_doctype": "Sales Invoice",
18 | "report_name": "HSN-wise-summary of outward supplies",
19 | "report_type": "Script Report",
20 | "roles": [
21 | {
22 | "role": "Accounts Manager"
23 | },
24 | {
25 | "role": "Accounts User"
26 | },
27 | {
28 | "role": "Auditor"
29 | }
30 | ]
31 | }
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Since version 2.23 (released in August 2019), git-blame has a feature
2 | # to ignore or bypass certain commits.
3 | #
4 | # This file contains a list of commits that are not likely what you
5 | # are looking for in a blame, such as mass reformatting or renaming.
6 | # You can set this file as a default ignore file for blame by running
7 | # the following command.
8 | #
9 | # $ git config blame.ignoreRevsFile .git-blame-ignore-revs
10 |
11 | # absolufy imports
12 | 79da1480c6187839aff417b99aea2e1b71014a00
13 |
14 | # formatting with black
15 | 702dd2a60de6957e0cddb1e82e887dd90124baa0
16 |
17 | # sort lines in hooks
18 | dec2438be2d63eff24da45d6c936ec846d8ab0df
19 |
20 | # refactor window.ic => window.india_compliance
21 | 38a53480c70a2c820049f023cbabbdaa3ea8aad6
22 |
23 | # updated black in pre-commit
24 | d8c2469651974cc82a2bb50c93e22f723cbb5b42
25 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/tax_category.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 |
4 |
5 | def validate(doc, method=None):
6 | if doc.get("gst_state") and frappe.db.get_value(
7 | "Tax Category",
8 | {
9 | "gst_state": doc.gst_state,
10 | "is_inter_state": doc.is_inter_state,
11 | "is_reverse_charge": doc.is_reverse_charge,
12 | },
13 | ):
14 | if doc.is_inter_state:
15 | frappe.throw(
16 | _("Inter State tax category for GST State {0} already exists").format(
17 | doc.gst_state
18 | )
19 | )
20 | else:
21 | frappe.throw(
22 | _("Intra State tax category for GST State {0} already exists").format(
23 | doc.gst_state
24 | )
25 | )
26 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_waybill_log/e_waybill_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Resilient Tech and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe import _
6 | from frappe.model.document import Document
7 |
8 | from india_compliance.gst_india.utils import send_updated_doc
9 | from india_compliance.gst_india.utils.e_waybill import _fetch_e_waybill_data
10 |
11 |
12 | class eWaybillLog(Document):
13 | def before_print(self, print_settings=None):
14 | if self.data and self.is_latest_data:
15 | return
16 |
17 | doc = frappe.get_doc(self.reference_doctype, self.reference_name)
18 | _fetch_e_waybill_data(doc, self)
19 | send_updated_doc(self)
20 | frappe.msgprint(
21 | _("Fetched latest e-Waybill data"), alert=True, indicator="green"
22 | )
23 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_vehicle_no_field_in_purchase_receipt.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | """
6 | 'lr_no' field is labeled as 'Vehicle Number' in Purchase Receipt(ERPNext).
7 | Values will be identified using regex pattern and updated to vehicle_no field.
8 | REGEX pattern will identify foll0wing sequences:
9 | - GJO6AB1234
10 | - gj 06 a 1234
11 | - gj06-ab-1234
12 | - Gj06 abc 1234
13 | """
14 | REGEX_PATTERN = r"^[a-zA-Z]{2}[-\s]?[0-9]{2}[-\s]?[a-zA-Z]{1,3}[-\s]?[0-9]{4}$"
15 | pr = frappe.qb.DocType("Purchase Receipt")
16 |
17 | (
18 | frappe.qb.update(pr)
19 | .set(pr.vehicle_no, pr.lr_no)
20 | .where(pr.lr_no.regexp(REGEX_PATTERN))
21 | .run()
22 | )
23 |
24 | (frappe.qb.update(pr).set(pr.lr_no, "").where(pr.lr_no.regexp(REGEX_PATTERN)).run())
25 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_purchase_register/gst_purchase_register.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2024-08-26 20:42:05.592632",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "letterhead": null,
12 | "modified": "2024-08-26 20:42:05.592632",
13 | "modified_by": "Administrator",
14 | "module": "GST India",
15 | "name": "GST Purchase Register",
16 | "owner": "Administrator",
17 | "prepared_report": 0,
18 | "ref_doctype": "Purchase Invoice",
19 | "report_name": "GST Purchase Register",
20 | "report_type": "Script Report",
21 | "roles": [
22 | {
23 | "role": "Purchase User"
24 | },
25 | {
26 | "role": "Accounts User"
27 | },
28 | {
29 | "role": "Auditor"
30 | },
31 | {
32 | "role": "Accounts Manager"
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/.github/workflows/linters.yml:
--------------------------------------------------------------------------------
1 | name: Linters
2 |
3 | on:
4 | workflow_call:
5 | pull_request:
6 | paths-ignore:
7 | - '**.md'
8 | - '**.csv'
9 |
10 | jobs:
11 |
12 | linters:
13 | name: linters
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v6
17 |
18 | - name: Set up Python 3.10
19 | uses: actions/setup-python@v6
20 | with:
21 | python-version: '3.10'
22 |
23 | - name: Install and Run Pre-commit
24 | uses: pre-commit/action@v3.0.1
25 |
26 | - name: Download Semgrep rules
27 | run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
28 |
29 | - name: Download semgrep
30 | run: pip install semgrep
31 |
32 | - name: Run Semgrep rules
33 | run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/hsn_wise_summary_of_inward_supplies/hsn_wise_summary_of_inward_supplies.py:
--------------------------------------------------------------------------------
1 | from india_compliance.gst_india.report.hsn_wise_summary_of_outward_supplies.hsn_wise_summary_of_outward_supplies import (
2 | get_columns,
3 | process_hsn_data,
4 | validate_filters,
5 | )
6 | from india_compliance.gst_india.utils.gstr3b.gstr3b_data import GSTR3BInvoices
7 |
8 |
9 | def execute(filters=None):
10 | if not filters:
11 | filters = {}
12 |
13 | validate_filters(filters)
14 |
15 | columns = get_columns(filters)
16 | data = get_data(filters)
17 |
18 | return columns, data
19 |
20 |
21 | def get_data(filters):
22 | _class = GSTR3BInvoices(filters)
23 | invoices = []
24 |
25 | for doctype in ("Purchase Invoice", "Bill of Entry"):
26 | invoices.extend(_class.get_data(doctype))
27 |
28 | return process_hsn_data(invoices)
29 |
--------------------------------------------------------------------------------
/india_compliance/patches/v16/remove_legacy_report_fixtures.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | legacy_reports = [
6 | "GSTR-1",
7 | "GST Sales Register Beta",
8 | "GST Purchase Register Beta",
9 | "GST Itemised Sales Register",
10 | "GST Itemised Purchase Register",
11 | ]
12 |
13 | try:
14 | reports = frappe.get_all(
15 | "Report",
16 | filters={"reference_report": ("in", legacy_reports)},
17 | fields="name",
18 | pluck="name",
19 | )
20 |
21 | frappe.delete_doc(
22 | "Report",
23 | legacy_reports + reports,
24 | force=True,
25 | ignore_permissions=True,
26 | delete_permanently=True,
27 | )
28 |
29 | except Exception:
30 | frappe.log_error(title="remove_legacy_report_fixtures failed")
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_waybill/e_waybill.json:
--------------------------------------------------------------------------------
1 | {
2 | "absolute_value": 0,
3 | "align_labels_right": 0,
4 | "creation": "2022-03-27 16:32:27.037976",
5 | "custom_format": 0,
6 | "default_print_language": "en",
7 | "disabled": 0,
8 | "doc_type": "e-Waybill Log",
9 | "docstatus": 0,
10 | "doctype": "Print Format",
11 | "font_size": 14,
12 | "html": "",
13 | "idx": 0,
14 | "line_breaks": 0,
15 | "margin_bottom": 0.0,
16 | "margin_left": 0.0,
17 | "margin_right": 0.0,
18 | "margin_top": 0.0,
19 | "modified": "2022-04-12 11:05:49.333577",
20 | "modified_by": "Administrator",
21 | "module": "GST India",
22 | "name": "e-Waybill",
23 | "owner": "Administrator",
24 | "page_number": "Hide",
25 | "print_format_builder": 0,
26 | "print_format_builder_beta": 0,
27 | "print_format_type": "Jinja",
28 | "raw_printing": 0,
29 | "show_section_headings": 0,
30 | "standard": "Yes"
31 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_waybill_detailed/e_waybill_detailed.json:
--------------------------------------------------------------------------------
1 | {
2 | "absolute_value": 0,
3 | "align_labels_right": 0,
4 | "creation": "2025-01-16 11:59:28.744326",
5 | "custom_format": 0,
6 | "default_print_language": "en",
7 | "disabled": 0,
8 | "doc_type": "e-Waybill Log",
9 | "docstatus": 0,
10 | "doctype": "Print Format",
11 | "font_size": 14,
12 | "idx": 0,
13 | "line_breaks": 0,
14 | "margin_bottom": 0.0,
15 | "margin_left": 0.0,
16 | "margin_right": 0.0,
17 | "margin_top": 0.0,
18 | "modified": "2025-01-21 10:42:52.756385",
19 | "modified_by": "Administrator",
20 | "module": "GST India",
21 | "name": "e-Waybill Detailed",
22 | "owner": "Administrator",
23 | "page_number": "Hide",
24 | "print_format_builder": 0,
25 | "print_format_builder_beta": 0,
26 | "print_format_type": "Jinja",
27 | "raw_printing": 0,
28 | "show_section_headings": 0,
29 | "standard": "Yes"
30 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/delivery_note.js:
--------------------------------------------------------------------------------
1 | const DOCTYPE = "Delivery Note";
2 | setup_e_waybill_actions(DOCTYPE);
3 |
4 | frappe.ui.form.on(DOCTYPE, {
5 | setup(frm) {
6 | frm.set_query("port_address", {
7 | filters: {
8 | country: "India",
9 | },
10 | });
11 | },
12 | refresh(frm) {
13 | if (!gst_settings.enable_e_waybill || !gst_settings.enable_e_waybill_from_dn)
14 | return;
15 | show_sandbox_mode_indicator();
16 | },
17 |
18 | after_save(frm) {
19 | if (is_e_waybill_applicable(frm) && !is_e_waybill_generatable(frm))
20 | frappe.show_alert(
21 | {
22 | message: __("Billing Address is required to create e-Waybill"),
23 | indicator: "yellow",
24 | },
25 | 10
26 | );
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_account_wise_summary/gst_account_wise_summary.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "add_translate_data": 0,
4 | "columns": [],
5 | "creation": "2025-04-25 16:27:21.521616",
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "letter_head": "",
13 | "letterhead": null,
14 | "modified": "2025-04-25 16:27:21.521616",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "GST Account-wise Summary",
18 | "owner": "Administrator",
19 | "prepared_report": 0,
20 | "ref_doctype": "Purchase Invoice",
21 | "report_name": "GST Account-wise Summary",
22 | "report_type": "Script Report",
23 | "roles": [
24 | {
25 | "role": "Accounts User"
26 | },
27 | {
28 | "role": "Auditor"
29 | },
30 | {
31 | "role": "Accounts Manager"
32 | }
33 | ],
34 | "timeout": 0
35 | }
36 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_tax_rate_wise_summary/gst_tax_rate_wise_summary.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "add_translate_data": 0,
4 | "columns": [],
5 | "creation": "2025-04-03 11:01:41.181976",
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "letter_head": "",
13 | "letterhead": null,
14 | "modified": "2025-04-03 12:09:20.116328",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "GST Tax Rate-wise Summary",
18 | "owner": "Administrator",
19 | "prepared_report": 0,
20 | "ref_doctype": "Sales Invoice",
21 | "report_name": "GST Tax Rate-wise Summary",
22 | "report_type": "Script Report",
23 | "roles": [
24 | {
25 | "role": "Accounts User"
26 | },
27 | {
28 | "role": "Accounts Manager"
29 | },
30 | {
31 | "role": "Auditor"
32 | }
33 | ],
34 | "timeout": 0
35 | }
36 |
--------------------------------------------------------------------------------
/.github/workflows/initiate_release.yml:
--------------------------------------------------------------------------------
1 |
2 | # This workflow is agnostic to branches. Only maintain on develop branch.
3 | # To add/remove versions just modify the matrix.
4 |
5 | name: Initiate Release
6 | on:
7 | workflow_dispatch:
8 |
9 | jobs:
10 | release:
11 | name: Release
12 | runs-on: ubuntu-latest
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | version: ["14", "15"]
17 |
18 | steps:
19 | - uses: octokit/request-action@v2.x
20 | with:
21 | route: POST /repos/{owner}/{repo}/pulls
22 | owner: resilient-tech
23 | repo: india-compliance
24 | title: |-
25 | "chore: release v${{ matrix.version }}"
26 | body: "Automated Release."
27 | base: version-${{ matrix.version }}
28 | head: version-${{ matrix.version }}-hotfix
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }}
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/print_format/e_invoice/e_invoice.json:
--------------------------------------------------------------------------------
1 | {
2 | "absolute_value": 0,
3 | "align_labels_right": 1,
4 | "creation": "2022-04-04 21:24:15.372327",
5 | "custom_format": 0,
6 | "default_print_language": "en-US",
7 | "disabled": 0,
8 | "doc_type": "Sales Invoice",
9 | "docstatus": 0,
10 | "doctype": "Print Format",
11 | "font": "Default",
12 | "font_size": 14,
13 | "html": "",
14 | "idx": 0,
15 | "line_breaks": 1,
16 | "margin_bottom": 15.0,
17 | "margin_left": 15.0,
18 | "margin_right": 15.0,
19 | "margin_top": 15.0,
20 | "modified": "2022-04-12 10:39:40.065409",
21 | "modified_by": "Administrator",
22 | "module": "GST India",
23 | "name": "e-Invoice",
24 | "owner": "Administrator",
25 | "page_number": "Hide",
26 | "print_format_builder": 0,
27 | "print_format_builder_beta": 0,
28 | "print_format_type": "Jinja",
29 | "raw_printing": 0,
30 | "show_section_headings": 1,
31 | "standard": "Yes"
32 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/bill_of_entry_summary/bill_of_entry_summary.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "add_translate_data": 0,
4 | "columns": [],
5 | "creation": "2023-05-08 12:24:58.886166",
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "letterhead": null,
13 | "modified": "2025-11-19 15:25:58.567516",
14 | "modified_by": "Administrator",
15 | "module": "GST India",
16 | "name": "Bill of Entry Summary",
17 | "owner": "Administrator",
18 | "prepared_report": 0,
19 | "ref_doctype": "Bill of Entry",
20 | "report_name": "Bill of Entry Summary",
21 | "report_type": "Script Report",
22 | "roles": [
23 | {
24 | "role": "Purchase User"
25 | },
26 | {
27 | "role": "Accounts User"
28 | },
29 | {
30 | "role": "Accounts Manager"
31 | },
32 | {
33 | "role": "Auditor"
34 | }
35 | ],
36 | "timeout": 0
37 | }
38 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/summary_of_itc_availed/summary_of_itc_availed.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "add_translate_data": 0,
4 | "columns": [],
5 | "creation": "2025-04-21 18:24:49.646289",
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "letterhead": null,
13 | "modified": "2025-04-21 18:26:50.175272",
14 | "modified_by": "Administrator",
15 | "module": "GST India",
16 | "name": "Summary of ITC Availed",
17 | "owner": "Administrator",
18 | "prepared_report": 0,
19 | "ref_doctype": "Purchase Invoice",
20 | "report_name": "Summary of ITC Availed",
21 | "report_type": "Script Report",
22 | "roles": [
23 | {
24 | "role": "Accounts User"
25 | },
26 | {
27 | "role": "Purchase User"
28 | },
29 | {
30 | "role": "Accounts Manager"
31 | },
32 | {
33 | "role": "Auditor"
34 | }
35 | ],
36 | "timeout": 0
37 | }
38 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/version.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 |
4 | from india_compliance.audit_trail.utils import (
5 | get_audit_trail_doctypes,
6 | is_audit_trail_enabled,
7 | )
8 |
9 |
10 | def validate(doc, method=None):
11 | if doc.is_new() or not is_audit_trail_enabled():
12 | return
13 |
14 | validate_protected_version(doc)
15 | if old_doc := doc.get_doc_before_save():
16 | validate_protected_version(old_doc)
17 |
18 |
19 | def on_trash(doc, method=None):
20 | if not is_audit_trail_enabled():
21 | return
22 |
23 | validate_protected_version(doc)
24 |
25 |
26 | def validate_protected_version(doc):
27 | if doc.ref_doctype in get_audit_trail_doctypes():
28 | frappe.throw(
29 | _(
30 | "Cannot alter Versions of {0}, since they are required for Audit Trail"
31 | ).format(_(doc.ref_doctype))
32 | )
33 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/number_card/pending_e_waybill/pending_e_waybill.json:
--------------------------------------------------------------------------------
1 | {
2 | "aggregate_function_based_on": "",
3 | "color": "#EC864B",
4 | "creation": "2023-08-04 11:30:55.485885",
5 | "docstatus": 0,
6 | "doctype": "Number Card",
7 | "document_type": "Sales Invoice",
8 | "dynamic_filters_json": "[]",
9 | "filters_json": "[[\"Sales Invoice\",\"e_waybill_status\",\"=\",\"Pending\"],[\"Sales Invoice\",\"docstatus\",\"=\",\"1\"]]",
10 | "function": "Count",
11 | "idx": 0,
12 | "is_public": 1,
13 | "is_standard": 1,
14 | "label": "Pending e-Waybills",
15 | "modified": "2025-11-21 18:02:20.611417",
16 | "modified_by": "Administrator",
17 | "module": "GST India",
18 | "name": "Pending e-Waybill",
19 | "owner": "Administrator",
20 | "parent_document_type": "",
21 | "report_function": "Sum",
22 | "show_full_number": 0,
23 | "show_percentage_stats": 0,
24 | "stats_time_interval": "Daily",
25 | "type": "Document Type"
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/semantic-commits.yml:
--------------------------------------------------------------------------------
1 | name: Semantic Commits
2 |
3 | on:
4 | pull_request: {}
5 |
6 | permissions:
7 | contents: read
8 |
9 | concurrency:
10 | group: commitcheck-frappe-${{ github.event.number }}
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | commitlint:
15 | name: Check Commit Titles
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v6
19 | with:
20 | fetch-depth: 200
21 |
22 | - uses: actions/setup-node@v6
23 | with:
24 | node-version: 20
25 | check-latest: true
26 |
27 | - name: Check commit titles
28 | run: |
29 | npm install @commitlint/cli @commitlint/config-conventional
30 | npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}
31 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/utils.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | import frappe.defaults
3 |
4 |
5 | def is_audit_trail_enabled():
6 | return bool(frappe.db.get_single_value("Accounts Settings", "enable_audit_trail"))
7 |
8 |
9 | @frappe.whitelist()
10 | def get_audit_trail_doctypes():
11 | return set(frappe.get_hooks("audit_trail_doctypes"))
12 |
13 |
14 | def enqueue_disable_audit_trail_notification():
15 | frappe.enqueue(
16 | "india_compliance.audit_trail.utils.disable_audit_trail_notification",
17 | queue="short",
18 | )
19 |
20 |
21 | @frappe.whitelist(methods=["POST"])
22 | def disable_audit_trail_notification():
23 | frappe.defaults.clear_user_default("needs_audit_trail_notification")
24 |
25 |
26 | @frappe.whitelist(methods=["POST"])
27 | def enable_audit_trail():
28 | accounts_settings = frappe.get_doc("Accounts Settings")
29 | accounts_settings.enable_audit_trail = 1
30 | accounts_settings.save()
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/gl_entry.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 |
4 | from india_compliance.gst_india.overrides.transaction import (
5 | is_indian_registered_company,
6 | )
7 | from india_compliance.gst_india.utils import get_all_gst_accounts
8 |
9 |
10 | def validate(doc, method=None):
11 | if doc.company_gstin or not is_indian_registered_company(doc):
12 | return
13 |
14 | gst_accounts = get_all_gst_accounts(doc.company)
15 | if doc.account not in gst_accounts:
16 | return
17 |
18 | frappe.throw(
19 | _(
20 | "Company GSTIN is a mandatory field for accounting of GST Accounts."
21 | " Run `Update GSTIN` patch from GST Balance Report to update GSTIN in all transactions."
22 | )
23 | )
24 |
25 |
26 | def update_gl_dict_with_regional_fields(doc, gl_dict):
27 | if doc.get("company_gstin"):
28 | gl_dict["company_gstin"] = doc.company_gstin
29 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "india_compliance"
3 | authors = [
4 | { name = "Resilient Tech", email = "hello@indiacompliance.app" }
5 | ]
6 | description = "ERPNext app to simplify compliance with Indian Rules and Regulations"
7 | readme = "README.md"
8 | dynamic = ["version"]
9 | dependencies = [
10 | "python-barcode~=0.15.1",
11 | "titlecase~=2.3",
12 | "pycryptodome~=3.19.0",
13 |
14 | # Not used directly - required by PyQRCode for PNG generation
15 | "pypng~=0.20220715.0",
16 | ]
17 |
18 | [build-system]
19 | requires = ["flit_core >=3.4,<4"]
20 | build-backend = "flit_core.buildapi"
21 |
22 | [tool.isort]
23 | profile = "black"
24 | known_frappe = "frappe"
25 | known_erpnext = "erpnext"
26 | no_lines_before = ["ERPNEXT"]
27 | sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FRAPPE", "ERPNEXT", "FIRSTPARTY", "LOCALFOLDER"]
28 |
29 | [tool.bench.dev-dependencies]
30 | parameterized = "~=0.8.1"
31 | time-machine = "~=2.10.0"
32 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/hsn_wise_summary_of_inward_supplies/hsn_wise_summary_of_inward_supplies.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "add_translate_data": 0,
4 | "columns": [],
5 | "creation": "2025-04-11 19:47:29.046936",
6 | "disabled": 0,
7 | "docstatus": 0,
8 | "doctype": "Report",
9 | "filters": [],
10 | "idx": 0,
11 | "is_standard": "Yes",
12 | "letter_head": "",
13 | "letterhead": null,
14 | "modified": "2025-04-11 19:47:29.046936",
15 | "modified_by": "Administrator",
16 | "module": "GST India",
17 | "name": "HSN-wise-summary of inward supplies",
18 | "owner": "Administrator",
19 | "prepared_report": 0,
20 | "ref_doctype": "Purchase Invoice",
21 | "report_name": "HSN-wise-summary of inward supplies",
22 | "report_type": "Script Report",
23 | "roles": [
24 | {
25 | "role": "Accounts User"
26 | },
27 | {
28 | "role": "Auditor"
29 | },
30 | {
31 | "role": "Accounts Manager"
32 | }
33 | ],
34 | "timeout": 0
35 | }
36 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/test_account_settings.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import frappe
4 | from frappe.tests import IntegrationTestCase
5 |
6 |
7 | class TestAccountsSettings(IntegrationTestCase):
8 | def test_validate_change_in_enable_audit_trail_and_validate_delete_linked_ledger_entries(
9 | self,
10 | ):
11 | doc = frappe.get_doc("Accounts Settings")
12 |
13 | doc.enable_audit_trail = 1
14 | doc.save()
15 |
16 | doc.delete_linked_ledger_entries = 1
17 | self.assertRaisesRegex(
18 | frappe.ValidationError,
19 | re.compile(r"cannot be enabled to ensure Audit Trail integrity$"),
20 | doc.save,
21 | )
22 |
23 | doc.reload()
24 |
25 | doc.enable_audit_trail = 0
26 | self.assertRaisesRegex(
27 | frappe.ValidationError,
28 | re.compile(r"^(Audit Trail cannot be disabled once enabled*)"),
29 | doc.save,
30 | )
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_hsn_code/gst_hsn_code.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on('GST HSN Code', {
5 | refresh: function(frm) {
6 | if(!frm.doc.__islocal){
7 | frm.add_custom_button(__('Update Taxes for Items'), function(){
8 | frappe.confirm(
9 | 'Are you sure? It will overwrite taxes for all items with HSN Code '+frm.doc.name+' .',
10 | function(){
11 | frappe.call({
12 | args:{
13 | taxes: frm.doc.taxes,
14 | hsn_code: frm.doc.name
15 | },
16 | method: 'india_compliance.gst_india.doctype.gst_hsn_code.gst_hsn_code.update_taxes_in_item_master',
17 | callback: function(r) {
18 | if(r.message){
19 | frappe.show_alert(__('Items with this HSN code will be updated shortly'));
20 | }
21 | }
22 | });
23 | }
24 | );
25 | });
26 | }
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/number_card/pending_e_invoices/pending_e_invoices.json:
--------------------------------------------------------------------------------
1 | {
2 | "aggregate_function_based_on": "",
3 | "color": "#EC864B",
4 | "creation": "2023-07-25 15:10:39.976867",
5 | "docstatus": 0,
6 | "doctype": "Number Card",
7 | "document_type": "Sales Invoice",
8 | "dynamic_filters_json": "[]",
9 | "filters_config": "",
10 | "filters_json": "[[\"Sales Invoice\",\"einvoice_status\",\"=\",\"Pending\"],[\"Sales Invoice\",\"docstatus\",\"=\",\"1\"]]",
11 | "function": "Count",
12 | "idx": 0,
13 | "is_public": 1,
14 | "is_standard": 1,
15 | "label": "Pending e-Invoices",
16 | "method": "",
17 | "modified": "2025-11-21 18:02:31.451315",
18 | "modified_by": "Administrator",
19 | "module": "GST India",
20 | "name": "Pending e-Invoices",
21 | "owner": "Administrator",
22 | "parent_document_type": "",
23 | "report_function": "Sum",
24 | "show_full_number": 0,
25 | "show_percentage_stats": 0,
26 | "stats_time_interval": "Daily",
27 | "type": "Document Type"
28 | }
29 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/add_company_link_to_einvoice_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull
3 |
4 |
5 | def execute():
6 | """
7 | update Company of E Invoice User from Dyanamic Link Table in Address
8 | """
9 |
10 | if not frappe.db.table_exists("E Invoice User"):
11 | return
12 |
13 | user = frappe.qb.DocType("E Invoice User", alias="user")
14 | address = frappe.qb.DocType("Address", alias="address")
15 | dynamic_link = frappe.qb.DocType("Dynamic Link", alias="dynamic_link")
16 | (
17 | frappe.qb.update(user)
18 | .join(address)
19 | .on(address.gstin == user.gstin)
20 | .join(dynamic_link)
21 | .on(
22 | (dynamic_link.parent == address.name)
23 | & (dynamic_link.link_doctype == "Company")
24 | )
25 | .set(user.company, dynamic_link.link_name)
26 | .where(IfNull(user.company, "") == "")
27 | .run()
28 | )
29 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/setup_custom_fields_for_gst.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.utils.custom_fields import delete_old_fields
4 |
5 |
6 | def execute():
7 | delete_tax_id_custom_field()
8 | set_correct_state_number()
9 | remove_shipping_fields_from_purchase_invoice()
10 |
11 |
12 | def delete_tax_id_custom_field():
13 | # delete custom field tax_id if it exists
14 | # this field was move to core ERPNext
15 | delete_old_fields("tax_id", ("Sales Order", "Sales Invoice", "Delivery Note"))
16 |
17 |
18 | def set_correct_state_number():
19 | # set correct state number for all states with single digit state number
20 | frappe.db.sql(
21 | """UPDATE tabAddress SET gst_state_number=concat("0", gst_state_number)
22 | WHERE length(gst_state_number) = 1"""
23 | )
24 |
25 |
26 | def remove_shipping_fields_from_purchase_invoice():
27 | delete_old_fields(
28 | ("port_code", "shipping_bill_number", "shipping_bill_date"), "Purchase Invoice"
29 | )
30 |
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_pending_boe_qty.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull, Sum
3 |
4 |
5 | def execute():
6 | pi = frappe.qb.DocType("Purchase Invoice")
7 | pi_item = frappe.qb.DocType("Purchase Invoice Item")
8 | boe_item = frappe.qb.DocType("Bill of Entry Item")
9 |
10 | submitted_boe_qty = (
11 | frappe.qb.from_(boe_item)
12 | .select(boe_item.pi_detail, Sum(boe_item.qty).as_("qty"))
13 | .where(boe_item.docstatus == 1)
14 | .groupby(boe_item.pi_detail)
15 | )
16 |
17 | (
18 | frappe.qb.update(pi_item)
19 | .join(pi)
20 | .on(pi_item.parent == pi.name)
21 | .left_join(submitted_boe_qty)
22 | .on(pi_item.name == submitted_boe_qty.pi_detail)
23 | .set(
24 | pi_item.pending_boe_qty,
25 | pi_item.qty - IfNull(submitted_boe_qty.qty, 0),
26 | )
27 | .where(pi.docstatus == 1)
28 | .where(pi.gst_category == "Overseas")
29 | .run()
30 | )
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/bill_of_entry_summary/bill_of_entry_summary.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.query_reports["Bill of Entry Summary"] = {
5 | "filters": [
6 | {
7 | "fieldname": "company",
8 | "label": __("Company"),
9 | "fieldtype": "Link",
10 | "options": "Company",
11 | "reqd": 1,
12 | "default": frappe.defaults.get_user_default("Company")
13 | },
14 | {
15 | "fieldname": "from_date",
16 | "label": __("From Date"),
17 | "fieldtype": "Date",
18 | "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
19 | "reqd": 1
20 | },
21 | {
22 | "fieldname": "to_date",
23 | "label": __("To Date"),
24 | "fieldtype": "Date",
25 | "default": frappe.datetime.get_today(),
26 | "reqd": 1
27 | },
28 | ]
29 | }
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/set_gst_tax_type_in_journal_entry.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder import Case
3 |
4 | from india_compliance.gst_india.utils import get_gst_account_gst_tax_type_map
5 |
6 |
7 | def execute():
8 | gst_account_tax_type_map = get_gst_account_gst_tax_type_map()
9 | if not gst_account_tax_type_map:
10 | return
11 |
12 | gst_accounts_by_tax_type = {}
13 | for account, tax_type in gst_account_tax_type_map.items():
14 | gst_accounts_by_tax_type.setdefault(tax_type, []).append(account)
15 |
16 | taxes_doctype = frappe.qb.DocType("Journal Entry Account")
17 |
18 | update_query = frappe.qb.update(taxes_doctype)
19 | conditions = Case()
20 |
21 | for gst_tax_account, gst_tax_name in gst_accounts_by_tax_type.items():
22 | conditions = conditions.when(
23 | taxes_doctype.account.isin(gst_tax_name), gst_tax_account
24 | )
25 | conditions = conditions.else_(None)
26 | update_query.set(taxes_doctype.gst_tax_type, conditions).run()
27 |
--------------------------------------------------------------------------------
/india_compliance/public/js/components/number_card.js:
--------------------------------------------------------------------------------
1 | frappe.provide("india_compliance");
2 |
3 | india_compliance.NumberCardManager = class NumberCardManager {
4 | constructor(opts) {
5 | Object.assign(this, opts);
6 | this.make_cards();
7 | this.show_summary();
8 | }
9 |
10 | make_cards() {
11 | this.$wrapper.empty();
12 | this.$cards = [];
13 | this.$summary = $(`
`)
14 | .hide()
15 | .appendTo(this.$wrapper);
16 |
17 | this.cards.forEach(summary => {
18 | let number_card = frappe.utils.build_summary_item(summary);
19 | this.$cards.push(number_card);
20 |
21 | number_card.appendTo(this.$summary);
22 | });
23 |
24 | this.$summary.css({
25 | "border-bottom": "0px",
26 | "margin-left": "0px",
27 | "margin-right": "0px",
28 | });
29 | }
30 |
31 | show_summary() {
32 | if (this.cards.length) this.$summary.show();
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | exclude: "node_modules|.git"
2 | default_stages: [commit]
3 | fail_fast: false
4 |
5 | repos:
6 | - repo: https://github.com/pre-commit/pre-commit-hooks
7 | rev: v4.5.0
8 | hooks:
9 | - id: trailing-whitespace
10 | files: "india_compliance.*"
11 | exclude: ".*json$|.*txt$|.*csv|.*md"
12 | - id: check-yaml
13 | - id: no-commit-to-branch
14 | args: ["--branch", "develop"]
15 | - id: check-merge-conflict
16 | - id: check-ast
17 |
18 | - repo: https://github.com/psf/black
19 | rev: 25.1.0
20 | hooks:
21 | - id: black
22 |
23 | - repo: https://github.com/PyCQA/isort
24 | rev: 6.0.0
25 | hooks:
26 | - id: isort
27 |
28 | - repo: https://github.com/PyCQA/flake8
29 | rev: 7.1.1
30 | hooks:
31 | - id: flake8
32 | additional_dependencies: [flake8-isort, flake8-bugbear]
33 |
34 | ci:
35 | autoupdate_schedule: weekly
36 | skip: []
37 | submodules: false
38 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/gst_job_work_stock_movement/gst_job_work_stock_movement.json:
--------------------------------------------------------------------------------
1 | {
2 | "add_total_row": 1,
3 | "columns": [],
4 | "creation": "2024-08-19 14:40:26.929838",
5 | "disabled": 0,
6 | "docstatus": 0,
7 | "doctype": "Report",
8 | "filters": [],
9 | "idx": 0,
10 | "is_standard": "Yes",
11 | "letterhead": null,
12 | "modified": "2024-08-19 14:40:33.093455",
13 | "modified_by": "Administrator",
14 | "module": "GST India",
15 | "name": "GST Job Work Stock Movement",
16 | "owner": "Administrator",
17 | "prepared_report": 0,
18 | "ref_doctype": "Subcontracting Order",
19 | "report_name": "GST Job Work Stock Movement",
20 | "report_type": "Script Report",
21 | "roles": [
22 | {
23 | "role": "Item Manager"
24 | },
25 | {
26 | "role": "Stock Manager"
27 | },
28 | {
29 | "role": "Stock User"
30 | },
31 | {
32 | "role": "Accounts Manager"
33 | },
34 | {
35 | "role": "Accounts User"
36 | },
37 | {
38 | "role": "Manufacturing Manager"
39 | },
40 | {
41 | "role": "Manufacturing User"
42 | }
43 | ]
44 | }
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_reconciliation_status_for_manual_match.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | """
6 | Match status was not being updated when manually matched. This patch will update the reconciliation status.
7 | """
8 | inward_supply = frappe.qb.DocType("GST Inward Supply")
9 | docs = (
10 | frappe.qb.from_(inward_supply)
11 | .select(inward_supply.link_doctype, inward_supply.link_name)
12 | .where(inward_supply.link_doctype.isin(("Purchase Invoice", "Bill of Entry")))
13 | .where(inward_supply.action == "No Action") # status updated on action
14 | .where(inward_supply.match_status == "Manual Match")
15 | .run(as_dict=True)
16 | )
17 |
18 | docs_to_update = {}
19 |
20 | for doc in docs:
21 | docs_to_update.setdefault(doc.link_doctype, []).append(doc.link_name)
22 |
23 | for doctype, doc_names in docs_to_update.items():
24 | frappe.db.set_value(
25 | doctype, {"name": ("in", doc_names)}, "reconciliation_status", "Match Found"
26 | )
27 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/update_return_logs_with_filing_preference.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.utils.gstin_info import (
4 | fetch_filing_preference,
5 | get_filing_preference,
6 | get_fy,
7 | )
8 |
9 |
10 | def patch_filing_preference(gstin):
11 | logs = frappe.get_all(
12 | "GST Return Log",
13 | filters={
14 | "filing_preference": ["is", "not set"],
15 | "gstin": gstin,
16 | "return_period": ["!=", "ALL"],
17 | "return_type": ["in", ["GSTR1", "GSTR3B"]],
18 | },
19 | fields=["name", "return_period", "gstin"],
20 | )
21 |
22 | if not logs:
23 | return
24 |
25 | gst_return_log = {}
26 | for log in logs:
27 | response = fetch_filing_preference(gstin, get_fy(log.return_period))
28 | preference = get_filing_preference(log.return_period, response)
29 | gst_return_log[log.name] = {"filing_preference": preference}
30 |
31 | frappe.db.bulk_update("GST Return Log", gst_return_log, update_modified=False)
32 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | ignore =
3 | B007,
4 | B950,
5 | E101,
6 | E111,
7 | E114,
8 | E116,
9 | E117,
10 | E121,
11 | E122,
12 | E123,
13 | E124,
14 | E125,
15 | E126,
16 | E127,
17 | E128,
18 | E131,
19 | E201,
20 | E202,
21 | E203,
22 | E211,
23 | E221,
24 | E222,
25 | E223,
26 | E224,
27 | E225,
28 | E226,
29 | E228,
30 | E231,
31 | E241,
32 | E242,
33 | E251,
34 | E261,
35 | E262,
36 | E265,
37 | E266,
38 | E271,
39 | E272,
40 | E273,
41 | E274,
42 | E301,
43 | E302,
44 | E303,
45 | E305,
46 | E306,
47 | E401,
48 | E402,
49 | E501,
50 | E502,
51 | E701,
52 | E702,
53 | E703,
54 | E741,
55 | F403,
56 | W191,
57 | W291,
58 | W292,
59 | W293,
60 | W391,
61 | W503,
62 | W504,
63 |
64 | per-file-ignores =
65 | # syntax: [comma-separated path/to/file: comma-separated ERROR CODES]
66 | __init__.py, hooks.py: F401
67 |
68 | max-line-length = 200
69 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/test_customize_form.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import frappe
4 | from frappe.tests import IntegrationTestCase
5 |
6 |
7 | class TestCustomizeFormAuditTrail(IntegrationTestCase):
8 | def test_validate_customize_form(self):
9 | customize_frm = self.get_customize_form()
10 | customize_frm.doc_type = "Purchase Invoice"
11 | customize_frm.save_customization()
12 |
13 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 1)
14 |
15 | customize_frm.track_changes = 0
16 | self.assertRaisesRegex(
17 | frappe.ValidationError,
18 | re.compile(r"^(Cannot disable Track Changes for*)"),
19 | customize_frm.save_customization,
20 | )
21 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 0)
22 |
23 | def get_customize_form(self, doctype=None):
24 | d = frappe.get_doc("Customize Form")
25 | if doctype:
26 | d.doc_type = doctype
27 | d.run_method("fetch_to_customize")
28 | return d
29 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/number_card/invoice_cancelled_but_not_e_invoice/invoice_cancelled_but_not_e_invoice.json:
--------------------------------------------------------------------------------
1 | {
2 | "aggregate_function_based_on": "",
3 | "color": "#EC864B",
4 | "creation": "2023-07-25 18:33:55.452360",
5 | "docstatus": 0,
6 | "doctype": "Number Card",
7 | "document_type": "Sales Invoice",
8 | "dynamic_filters_json": "[]",
9 | "filters_json": "[[\"Sales Invoice\",\"einvoice_status\",\"=\",\"Pending Cancellation\"],[\"Sales Invoice\",\"docstatus\",\"=\",\"2\"],[\"Sales Invoice\",\"irn\",\"is\",\"set\"]]",
10 | "function": "Count",
11 | "idx": 0,
12 | "is_public": 1,
13 | "is_standard": 1,
14 | "label": "Active e-Invoice, Cancelled Invoice",
15 | "method": "",
16 | "modified": "2025-11-21 18:02:11.655081",
17 | "modified_by": "Administrator",
18 | "module": "GST India",
19 | "name": "Invoice Cancelled But Not e-Invoice",
20 | "owner": "Administrator",
21 | "parent_document_type": "",
22 | "report_function": "Sum",
23 | "show_full_number": 0,
24 | "show_percentage_stats": 0,
25 | "stats_time_interval": "Daily",
26 | "type": "Document Type"
27 | }
28 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/router.js:
--------------------------------------------------------------------------------
1 | import AuthPage from "./pages/AuthPage.vue";
2 | import AccountPage from "./pages/AccountPage.vue";
3 | import MailSentPage from "./pages/MailSentPage.vue";
4 | import PurchaseCreditsPage from "./pages/PurchaseCreditsPage.vue";
5 | import PaymentPage from "./pages/PaymentPage.vue";
6 |
7 | export const routes = [
8 | {
9 | name: "auth",
10 | path: "/authentication",
11 | component: AuthPage,
12 | },
13 | {
14 | name: "mailSent",
15 | path: "/mail-sent",
16 | component: MailSentPage,
17 | },
18 | {
19 | name: "purchaseCredits",
20 | path: "/purchase-credits",
21 | component: PurchaseCreditsPage,
22 | },
23 | {
24 | name: "paymentPage",
25 | path: "/payment-page",
26 | component: PaymentPage,
27 | },
28 | {
29 | name: "home",
30 | path: "/",
31 | component: AccountPage,
32 | alias: "/account",
33 | },
34 | ];
35 |
36 | export const AUTH_ROUTES = ["auth", "mailSent"];
37 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/company_print_options/company_print_options.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2024-05-24 10:38:39.591721",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "print_label",
10 | "print_value"
11 | ],
12 | "fields": [
13 | {
14 | "allow_in_quick_entry": 1,
15 | "columns": 2,
16 | "fieldname": "print_label",
17 | "fieldtype": "Autocomplete",
18 | "in_list_view": 1,
19 | "label": "Print Label",
20 | "search_index": 1
21 | },
22 | {
23 | "columns": 2,
24 | "fieldname": "print_value",
25 | "fieldtype": "Data",
26 | "in_list_view": 1,
27 | "label": "Print Value"
28 | }
29 | ],
30 | "index_web_pages_for_search": 1,
31 | "istable": 1,
32 | "links": [],
33 | "modified": "2024-06-26 16:55:21.621320",
34 | "modified_by": "Administrator",
35 | "module": "GST India",
36 | "name": "Company Print Options",
37 | "owner": "Administrator",
38 | "permissions": [],
39 | "sort_field": "creation",
40 | "sort_order": "DESC",
41 | "states": []
42 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/test_party.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.tests import IntegrationTestCase
3 |
4 |
5 | class TestUtils(IntegrationTestCase):
6 | def test_validate_new_party(self):
7 | party = frappe.new_doc(
8 | "Customer", customer_name="Resilient Tech", gstin="24AUTPV8831F1ZZ"
9 | )
10 | party.save()
11 |
12 | self.assertEqual(party.gst_category, "Registered Regular")
13 |
14 | def test_validate_deemed_export_party(self):
15 | party = frappe.new_doc(
16 | "Customer",
17 | customer_name="Resilient Tech",
18 | gstin="24AUTPV8831F1ZZ",
19 | gst_category="Deemed Export",
20 | )
21 | party.save()
22 |
23 | self.assertEqual(party.gst_category, "Deemed Export")
24 |
25 | def test_validate_new_party_with_tcs(self):
26 | # Allow TCS GSTIN
27 | party = frappe.new_doc(
28 | "Customer",
29 | customer_name="Flipkart India Private Limited",
30 | gstin="29AABCF8078M1C8",
31 | )
32 |
33 | party.insert()
34 |
--------------------------------------------------------------------------------
/india_compliance/exceptions.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | class GSPServerError(frappe.ValidationError):
5 | message = "GSP/GST server is down"
6 | title = "GSP/GST Server Error"
7 |
8 |
9 | class GSPLimitExceededError(GSPServerError):
10 | message = "GSP/GST account limit exceeded"
11 | http_status_code = 429
12 |
13 |
14 | class GatewayTimeoutError(GSPServerError):
15 | message = "The server took too long to respond"
16 | http_status_code = 504
17 |
18 |
19 | class OTPRequestedError(Exception):
20 | def __init__(self, message="OTP has been requested", *args, **kwargs):
21 | self.response = kwargs.pop("response", None)
22 | super().__init__(message, *args, **kwargs)
23 |
24 |
25 | class InvalidOTPError(Exception):
26 | def __init__(self, message="Invalid OTP", *args, **kwargs):
27 | self.response = kwargs.pop("response", None)
28 | super().__init__(message, *args, **kwargs)
29 |
30 |
31 | class InvalidAuthTokenError(Exception):
32 | def __init__(self, message="Invalid Auth Token", *args, **kwargs):
33 | super().__init__(message, *args, **kwargs)
34 |
--------------------------------------------------------------------------------
/india_compliance/vat_india/doctype/c_form/c_form.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 | // License: GNU General Public License v3. See license.txt
3 |
4 | //c-form js file
5 | // -----------------------------
6 |
7 | frappe.ui.form.on('C-Form', {
8 | setup(frm) {
9 | frm.fields_dict.invoices.grid.get_field("invoice_no").get_query = function(doc) {
10 | return {
11 | filters: {
12 | "docstatus": 1,
13 | "customer": doc.customer,
14 | "company": doc.company,
15 | "c_form_applicable": 'Yes',
16 | "c_form_no": ''
17 | }
18 | };
19 | }
20 |
21 | frm.fields_dict.state.get_query = function() {
22 | return {
23 | filters: {
24 | country: "India"
25 | }
26 | };
27 | }
28 | }
29 | });
30 |
31 | frappe.ui.form.on('C-Form Invoice Detail', {
32 | invoice_no(frm, cdt, cdn) {
33 | let d = frappe.get_doc(cdt, cdn);
34 |
35 | if (d.invoice_no) {
36 | frm.call('get_invoice_details', {
37 | invoice_no: d.invoice_no
38 | }).then(r => {
39 | frappe.model.set_value(cdt, cdn, r.message);
40 | });
41 | }
42 | }
43 | });
44 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/accounts_settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 |
4 | from india_compliance.audit_trail.setup import create_property_setters_for_versioning
5 |
6 |
7 | def validate(doc, method=None):
8 | validate_change_in_enable_audit_trail(doc)
9 | validate_delete_linked_ledger_entries(doc)
10 |
11 |
12 | def validate_change_in_enable_audit_trail(doc):
13 | if not doc.has_value_changed("enable_audit_trail"):
14 | return
15 |
16 | if not doc.enable_audit_trail:
17 | frappe.throw(_("Audit Trail cannot be disabled once enabled"))
18 |
19 | # Enable audit trail
20 | doc.delete_linked_ledger_entries = 0
21 | frappe.enqueue(create_property_setters_for_versioning, queue="short", at_front=True)
22 |
23 |
24 | def validate_delete_linked_ledger_entries(doc):
25 | if doc.enable_audit_trail and doc.delete_linked_ledger_entries:
26 | frappe.throw(
27 | _("{0} cannot be enabled to ensure Audit Trail integrity").format(
28 | frappe.bold(doc.meta.get_label("delete_linked_ledger_entries"))
29 | )
30 | )
31 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/e_invoice_applicable_company/e_invoice_applicable_company.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2023-05-09 09:18:21.328069",
5 | "default_view": "List",
6 | "doctype": "DocType",
7 | "editable_grid": 1,
8 | "engine": "InnoDB",
9 | "field_order": [
10 | "company",
11 | "applicable_from"
12 | ],
13 | "fields": [
14 | {
15 | "fieldname": "company",
16 | "fieldtype": "Link",
17 | "in_list_view": 1,
18 | "label": "Company",
19 | "options": "Company",
20 | "reqd": 1
21 | },
22 | {
23 | "default": "Today",
24 | "fieldname": "applicable_from",
25 | "fieldtype": "Date",
26 | "in_list_view": 1,
27 | "label": "Applicable From",
28 | "reqd": 1
29 | }
30 | ],
31 | "index_web_pages_for_search": 1,
32 | "istable": 1,
33 | "links": [],
34 | "modified": "2024-03-29 11:36:18.788811",
35 | "modified_by": "Administrator",
36 | "module": "GST India",
37 | "name": "e-Invoice Applicable Company",
38 | "owner": "Administrator",
39 | "permissions": [],
40 | "sort_field": "creation",
41 | "sort_order": "DESC",
42 | "states": []
43 | }
--------------------------------------------------------------------------------
/.github/workflows/on_release.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Generate Semantic Release
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - version-14
8 | - version-15
9 | jobs:
10 | release:
11 | name: Release
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout Entire Repository
15 | uses: actions/checkout@v6
16 | with:
17 | fetch-depth: 0
18 | persist-credentials: false
19 |
20 | - name: Setup Node.js
21 | uses: actions/setup-node@v6
22 | with:
23 | node-version: 20
24 |
25 | - name: Setup dependencies
26 | run: |
27 | npm install @semantic-release/git @semantic-release/exec --no-save
28 | - name: Create Release
29 | env:
30 | GH_TOKEN: ${{ secrets.BOT_TOKEN }}
31 | GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }}
32 | GIT_AUTHOR_NAME: "India Compliance Bot"
33 | GIT_AUTHOR_EMAIL: "bot@indiacompliance.app"
34 | GIT_COMMITTER_NAME: "India Compliance Bot"
35 | GIT_COMMITTER_EMAIL: "bot@indiacompliance.app"
36 | run: npx semantic-release
37 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/constants/custom_fields.py:
--------------------------------------------------------------------------------
1 | CUSTOM_FIELDS = {
2 | "Accounts Settings": [
3 | {
4 | "fieldname": "audit_trail_section",
5 | "fieldtype": "Section Break",
6 | "label": "Audit Trail",
7 | "insert_after": "invoice_and_billing_tab",
8 | "collapsible": 1,
9 | "collapsible_depends_on": "eval: !doc.enable_audit_trail",
10 | },
11 | {
12 | "fieldname": "enable_audit_trail",
13 | "fieldtype": "Check",
14 | "label": "Enable Audit Trail",
15 | "description": (
16 | "In accordance with MCA Notification dated 24-03-2021 , enabling this"
19 | " feature will ensure that each change made to the books of account"
20 | " gets recorded. Once enabled, this feature cannot be disabled."
21 | ),
22 | "insert_after": "audit_trail_section",
23 | },
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/migrate_fields_for_gstr3b.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | if not frappe.db.has_column("GSTR 3B Report", "month"):
6 | return
7 |
8 | # Update month_or_quarter from month field
9 | gstr3b_report = frappe.qb.DocType("GSTR 3B Report")
10 |
11 | (
12 | frappe.qb.update(gstr3b_report)
13 | .set(gstr3b_report.month_or_quarter, gstr3b_report.month)
14 | .run()
15 | )
16 |
17 | # Update company_gstin based on company_address
18 | addresses = frappe.get_all("GSTR 3B Report", pluck="company_address", distinct=True)
19 |
20 | for address in addresses:
21 | frappe.db.set_value(
22 | "GSTR 3B Report",
23 | {"company_address": address},
24 | "company_gstin",
25 | get_gstin_based_on_address(address),
26 | )
27 |
28 |
29 | def get_gstin_based_on_address(address):
30 | """Get GSTIN based on company_address or company"""
31 | return (
32 | frappe.db.get_value(
33 | "Address",
34 | address,
35 | "gstin",
36 | )
37 | or ""
38 | )
39 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/journal_entry.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 |
4 | from india_compliance.gst_india.overrides.transaction import (
5 | is_indian_registered_company,
6 | )
7 | from india_compliance.gst_india.utils import get_gst_account_gst_tax_type_map
8 |
9 |
10 | def set_gst_tax_type(doc, method=None):
11 | if not doc.accounts:
12 | return
13 |
14 | gst_tax_account_map = get_gst_account_gst_tax_type_map()
15 | if not gst_tax_account_map:
16 | return
17 |
18 | for tax in doc.accounts:
19 | # Setting as None if not GST Account
20 | tax.gst_tax_type = gst_tax_account_map.get(tax.account)
21 |
22 |
23 | def validate(doc, method=None):
24 | if doc.company_gstin or not is_indian_registered_company(doc):
25 | return
26 |
27 | set_gst_tax_type(doc)
28 |
29 | # validate company_gstin
30 | contains_gst_account = False
31 | for row in doc.accounts:
32 | if row.gst_tax_type:
33 | contains_gst_account = True
34 | break
35 |
36 | if contains_gst_account:
37 | frappe.throw(_("Company GSTIN is mandatory if any GST account is present."))
38 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_reverse_charge_and_export_type.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.utils.custom_fields import delete_old_fields
4 |
5 | DOCTYPES = ("Purchase Invoice", "Sales Invoice")
6 |
7 |
8 | def get_doctype_columns(doctypes):
9 | return {doctype: frappe.db.get_table_columns(doctype) for doctype in doctypes}
10 |
11 |
12 | def execute():
13 | update_field_to_check("reverse_charge", "is_reverse_charge", "Y")
14 | update_field_to_check("export_type", "is_export_with_gst", "With Payment of Tax")
15 |
16 |
17 | def update_field_to_check(old_fieldname, new_fieldname, truthy_value):
18 | for doctype, columns in get_doctype_columns(DOCTYPES).items():
19 | # Check for new fieldname, is_export_with_gst is only applicable for Sales Invoice
20 | if old_fieldname not in columns or new_fieldname not in columns:
21 | continue
22 |
23 | frappe.db.set_value(doctype, {old_fieldname: truthy_value}, new_fieldname, 1)
24 | frappe.db.sql_ddl(
25 | "alter table `tab{0}` drop column {1}".format(doctype, old_fieldname)
26 | )
27 |
28 | delete_old_fields(old_fieldname, DOCTYPES)
29 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/auth/MarketingInfoCheckIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
15 |
16 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/purchase_reconciliation_tool/gstr_download_history.html:
--------------------------------------------------------------------------------
1 |
2 | {% if typeof(data) == "string" %}
3 |
{{ data }}
4 | {% else %}
5 |
6 |
7 |
8 | {% for(let i=0; i{{ columns[i] }}
10 | {% } %}
11 |
12 |
13 |
14 | {% for(let [period, list] of data) { %}
15 |
16 | {{period}}
17 | {{ list[0] }}
18 |
19 |
20 | {% for(let i=1;i < list.length;i++){ %}
21 |
22 | {{ list[i] }}
23 |
24 | {% } %}
25 |
26 | {% } %}
27 |
28 |
29 |
30 | {% endif %}
31 |
--------------------------------------------------------------------------------
/india_compliance/public/js/regex_constants.js:
--------------------------------------------------------------------------------
1 | // Copied from india_compliance/gst_india/constants
2 |
3 | const NORMAL = "^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[Z1-9ABD-J]{1}[0-9A-Z]{1}$";
4 | const GOVT_DEPTID = "^[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z]{1}[0-9]{1}[Z]{1}[0-9]{1}$";
5 | const NRI_ID = "^[0-9]{4}[A-Z]{3}[0-9]{5}[N][R][0-9A-Z]{1}$";
6 | const OIDAR = "^[9][9][0-9]{2}[A-Z]{3}[0-9]{5}[O][S][0-9A-Z]{1}$";
7 | const UNBODY = "^[0-9]{4}[A-Z]{3}[0-9]{5}[UO]{1}[N][A-Z0-9]{1}$";
8 | const TDS = "^[0-9]{2}[A-Z]{4}[A-Z0-9]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[D][0-9A-Z]$";
9 | const TCS = "^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[C]{1}[0-9A-Z]{1}$";
10 |
11 | export const REGISTERED_REGEX = new RegExp([NORMAL, GOVT_DEPTID].join("|"));
12 | export const OVERSEAS_REGEX = new RegExp([NRI_ID, OIDAR].join("|"));
13 | export const UNBODY_REGEX = new RegExp(UNBODY);
14 | export const TDS_REGEX = new RegExp(TDS);
15 | export const TCS_REGEX = new RegExp(TCS);
16 |
17 | export const GSTIN_REGEX = new RegExp(
18 | [NORMAL, GOVT_DEPTID, NRI_ID, OIDAR, UNBODY, TDS, TCS].join("|")
19 | );
20 |
21 | export const GST_INVOICE_NUMBER_FORMAT = new RegExp("^[^\\W_][A-Za-z\\d\\-/]{0,15}$");
22 | export const PAN_REGEX = new RegExp("^[A-Z]{5}[0-9]{4}[A-Z]{1}$");
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/manual_patch_to_update_gst_details.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.patches.post_install.improve_item_tax_template import (
4 | TRANSACTION_ITEM_DOCTYPES,
5 | get_indian_companies,
6 | update_gst_details_for_transactions,
7 | update_gst_treatment_for_transactions,
8 | )
9 | from india_compliance.patches.post_install.set_gst_tax_type import (
10 | execute as set_gst_tax_type,
11 | )
12 | from india_compliance.patches.post_install.set_gst_tax_type_in_journal_entry import (
13 | execute as set_gst_tax_type_in_journal_entry,
14 | )
15 |
16 |
17 | def execute():
18 | reset_gst_treatment()
19 | set_gst_tax_type()
20 | set_gst_tax_type_in_journal_entry()
21 | update_gst_treatment_for_transactions()
22 |
23 | companies = get_indian_companies()
24 | update_gst_details_for_transactions(companies)
25 |
26 |
27 | def reset_gst_treatment():
28 | for item_doctype in TRANSACTION_ITEM_DOCTYPES:
29 | # GST Treatment is not required in Material Request Item
30 | if item_doctype == "Material Request Item":
31 | continue
32 |
33 | table = frappe.qb.DocType(item_doctype)
34 | frappe.qb.update(table).set(table.gst_treatment, "").run()
35 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/remove_old_fields.py:
--------------------------------------------------------------------------------
1 | from india_compliance.utils.custom_fields import delete_old_fields
2 |
3 |
4 | def execute():
5 | delete_old_fields(
6 | "customer_gstin",
7 | (
8 | "Quotation",
9 | "Sales Order",
10 | "Delivery Note",
11 | "Sales Invoice",
12 | "POS Invoice",
13 | ),
14 | )
15 |
16 | delete_old_fields(
17 | ("reason_for_issuing_document", "ecommerce_gstin"), "Purchase Invoice"
18 | )
19 | delete_old_fields("pan_details", "Company")
20 | delete_old_fields("export_type", ("Customer", "Supplier"))
21 | delete_old_fields("company_address", "Journal Entry")
22 | delete_old_fields("reason_for_issuing_document", "Sales Invoice")
23 |
24 | # Field renamed post release
25 | delete_old_fields(
26 | ("custom_gst_breakup", "custom_gst_breakup_table"),
27 | (
28 | "Supplier Quotation",
29 | "Purchase Order",
30 | "Purchase Receipt",
31 | "Purchase Invoice",
32 | "Quotation",
33 | "Sales Order",
34 | "Delivery Note",
35 | "Sales Invoice",
36 | "POS Invoice",
37 | ),
38 | )
39 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/purchase_receipt.js:
--------------------------------------------------------------------------------
1 | const DOCTYPE = "Purchase Receipt";
2 | setup_e_waybill_actions(DOCTYPE);
3 |
4 | frappe.ui.form.on(DOCTYPE, {
5 | setup(frm) {
6 | frm.set_query("transporter", {
7 | filters: {
8 | is_transporter: 1,
9 | },
10 | });
11 |
12 | frm.set_query("driver", doc => {
13 | return {
14 | filters: {
15 | transporter: doc.transporter,
16 | },
17 | };
18 | });
19 | },
20 |
21 | refresh(frm) {
22 | if (gst_settings.enable_e_waybill && gst_settings.enable_e_waybill_from_pr)
23 | show_sandbox_mode_indicator();
24 | },
25 |
26 | after_save(frm) {
27 | if (
28 | frm.doc.supplier_address ||
29 | !(frm.doc.gst_category == "Unregistered" || frm.doc.is_return) ||
30 | !is_e_waybill_applicable(frm) ||
31 | !has_e_waybill_threshold_met(frm)
32 | )
33 | return;
34 |
35 | frappe.show_alert(
36 | {
37 | message: __("Supplier Address is required to create e-Waybill"),
38 | indicator: "yellow",
39 | },
40 | 10
41 | );
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/test_sales_invoice.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.tests import IntegrationTestCase
3 |
4 | from india_compliance.gst_india.utils import validate_invoice_number
5 |
6 |
7 | class TestSalesInvoice(IntegrationTestCase):
8 | def test_validate_invoice_number(self):
9 | posting_date = "2021-05-01"
10 |
11 | invalid_names = [
12 | "SI$1231",
13 | "012345678901234567",
14 | "SI 2020 05",
15 | "SI.2020.0001",
16 | "PI2021 - 001",
17 | ]
18 | for name in invalid_names:
19 | doc = frappe._dict(
20 | name=name, posting_date=posting_date, doctype="Sales Invoice"
21 | )
22 | self.assertRaises(frappe.ValidationError, validate_invoice_number, doc)
23 |
24 | valid_names = [
25 | "012345678901236",
26 | "SI/2020/0001",
27 | "SI/2020-0001",
28 | "2020-PI-0001",
29 | "PI2020-0001",
30 | ]
31 | for name in valid_names:
32 | doc = frappe._dict(name=name, posting_date=posting_date)
33 | try:
34 | validate_invoice_number(doc)
35 | except frappe.ValidationError:
36 | self.fail("Valid name {} throwing error".format(name))
37 |
--------------------------------------------------------------------------------
/india_compliance/test_patches.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.modules.patch_handler import get_patches_from_app
3 | from frappe.tests import IntegrationTestCase
4 |
5 | from india_compliance.install import POST_INSTALL_PATCHES
6 |
7 |
8 | class TestPatches(IntegrationTestCase):
9 | def test_post_install_patch_exists(self):
10 | for patch in POST_INSTALL_PATCHES:
11 | self.assertTrue(
12 | frappe.get_attr(
13 | f"india_compliance.patches.post_install.{patch}.execute"
14 | )
15 | )
16 |
17 | def test_patches_exists(self):
18 | patches = get_patches_from_app("india_compliance")
19 |
20 | for patch in patches:
21 | if patch.startswith("execute:"):
22 | import_path = patch.split("execute:")[1]
23 |
24 | if not import_path.startswith("from"):
25 | continue
26 |
27 | components = import_path.split("from")[1].split()
28 | module = components[0]
29 | function_name = components[2].replace(";", "").replace(",", "")
30 | patch_path = module + "." + function_name
31 | else:
32 | patch_path = f"{patch.split(maxsplit=1)[0]}.execute"
33 |
34 | frappe.get_attr(patch_path)
35 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/Loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
32 |
33 |
--------------------------------------------------------------------------------
/india_compliance/patches/v15/migrate_boe_taxes_to_ic_taxes.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.model.document import bulk_insert
3 | from frappe.model.naming import _generate_random_string
4 |
5 |
6 | def execute():
7 | if not frappe.db.table_exists("Bill of Entry Taxes"):
8 | return
9 |
10 | boe_taxes = frappe.qb.DocType("Bill of Entry Taxes")
11 | boe_taxes_docs = frappe.qb.from_(boe_taxes).select("*").run(as_dict=True)
12 |
13 | ic_taxes_names = set(
14 | frappe.get_all("India Compliance Taxes and Charges", pluck="name")
15 | )
16 | ic_taxes = []
17 |
18 | for doc in boe_taxes_docs:
19 | ic_taxes_doc = frappe.get_doc(
20 | {
21 | **doc,
22 | "doctype": "India Compliance Taxes and Charges",
23 | "name": set_name(doc.name, ic_taxes_names),
24 | "base_total": doc.total,
25 | }
26 | )
27 |
28 | ic_taxes.append(ic_taxes_doc)
29 |
30 | bulk_insert("India Compliance Taxes and Charges", ic_taxes)
31 |
32 | # Drop the old table
33 | frappe.db.delete("Bill of Entry Taxes")
34 |
35 |
36 | def set_name(name, names):
37 | new_name = name
38 | while new_name in names:
39 | new_name = _generate_random_string(10)
40 |
41 | names.add(new_name)
42 | return new_name
43 |
--------------------------------------------------------------------------------
/india_compliance/uninstall.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | from india_compliance.gst_india.constants import BUG_REPORT_URL
4 | from india_compliance.gst_india.uninstall import before_uninstall as remove_gst
5 | from india_compliance.gst_india.uninstall import (
6 | delete_education_custom_fields,
7 | delete_healthcare_custom_fields,
8 | delete_hrms_custom_fields,
9 | )
10 | from india_compliance.income_tax_india.uninstall import (
11 | before_uninstall as remove_income_tax,
12 | )
13 |
14 |
15 | def before_uninstall():
16 | try:
17 | print("Removing Income Tax customizations...")
18 | remove_income_tax()
19 |
20 | print("Removing GST customizations...")
21 | remove_gst()
22 |
23 | except Exception as e:
24 | click.secho(
25 | (
26 | "Removing customizations for India Compliance failed due to an error."
27 | " Please try again or"
28 | f" report the issue on {BUG_REPORT_URL} if not resolved."
29 | ),
30 | fg="bright_red",
31 | )
32 | raise e
33 |
34 |
35 | def before_app_uninstall(app_name):
36 | if app_name == "hrms":
37 | delete_hrms_custom_fields()
38 |
39 | if app_name == "education":
40 | delete_education_custom_fields()
41 |
42 | if app_name == "healthcare":
43 | delete_healthcare_custom_fields()
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
22 |
23 | > Please provide enough information so that others can review your pull request:
24 |
25 |
26 |
27 | > Explain the **details** for making this change. What existing problem does the pull request solve?
28 |
29 |
30 |
31 | > Screenshots/GIFs
32 |
33 |
34 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/unreconcile_payment.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from erpnext.accounts.general_ledger import make_reverse_gl_entries
3 |
4 |
5 | def before_submit(doc, method=None):
6 | if doc.voucher_type != "Payment Entry":
7 | return
8 |
9 | for allocation in doc.allocations:
10 | voucher_detail_nos = frappe.get_all(
11 | "Payment Entry Reference",
12 | {
13 | "parent": doc.voucher_no,
14 | "reference_doctype": allocation.reference_doctype,
15 | "reference_name": allocation.reference_name,
16 | "docstatus": 1,
17 | },
18 | pluck="name",
19 | )
20 |
21 | for voucher_detail_no in voucher_detail_nos:
22 | reverse_gst_adjusted_against_payment_entry(
23 | voucher_detail_no, doc.voucher_no
24 | )
25 |
26 |
27 | def reverse_gst_adjusted_against_payment_entry(voucher_detail_no, payment_name):
28 | filters = {
29 | "voucher_type": "Payment Entry",
30 | "voucher_no": payment_name,
31 | "voucher_detail_no": voucher_detail_no,
32 | }
33 |
34 | gl_entries = frappe.get_all("GL Entry", filters=filters, fields="*")
35 | if not gl_entries:
36 | return
37 |
38 | frappe.db.set_value("GL Entry", filters, "is_cancelled", 1)
39 | make_reverse_gl_entries(gl_entries, partial_cancel=True)
40 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/report/india_compliance_api_usage/india_compliance_api_usage.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Resilient Tech and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.query_reports["India Compliance API Usage"] = {
5 | filters: [
6 | {
7 | "fieldname": "from_date",
8 | "label": __("From"),
9 | "fieldtype": "Date",
10 | "reqd": 1,
11 | "default": frappe.datetime.add_months(frappe.datetime.now_date(), -6)
12 | },
13 | {
14 | "fieldname": "to_date",
15 | "label": __("To"),
16 | "fieldtype": "Date",
17 | "reqd": 1,
18 | "default": frappe.datetime.now_date()
19 | },
20 | {
21 | "fieldname": "report_by",
22 | "label": __("Report by"),
23 | "fieldtype": "Select",
24 | "options": [
25 | "Endpoint",
26 | "Linked Document",
27 | "Date"
28 | ],
29 | "default": "Endpoint"
30 | },
31 | ],
32 |
33 | onload(query_report) {
34 | query_report.filters.forEach(filter => {
35 | if (filter.fieldtype === "Date") {
36 | filter.datepicker.update(
37 | { maxDate: new Date() }
38 | )
39 | }
40 | });
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/customize_form.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 | from frappe.custom.doctype.customize_form.customize_form import (
4 | CustomizeForm as _CustomizeForm,
5 | )
6 |
7 | from india_compliance.audit_trail.utils import (
8 | get_audit_trail_doctypes,
9 | is_audit_trail_enabled,
10 | )
11 |
12 |
13 | class CustomizeForm(_CustomizeForm):
14 | @frappe.whitelist()
15 | def fetch_to_customize(self):
16 | self.set_onload(
17 | "audit_trail_enabled",
18 | self.doc_type
19 | and is_audit_trail_enabled()
20 | and self.doc_type in get_audit_trail_doctypes(),
21 | )
22 |
23 | return super().fetch_to_customize()
24 |
25 | @frappe.whitelist()
26 | def save_customization(self):
27 | self.validate_audit_trail_integrity()
28 | return super().save_customization()
29 |
30 | def validate_audit_trail_integrity(self):
31 | if (
32 | not self.doc_type
33 | or self.track_changes
34 | or not is_audit_trail_enabled()
35 | or self.doc_type not in get_audit_trail_doctypes()
36 | ):
37 | return
38 |
39 | frappe.throw(
40 | _(
41 | "Cannot disable Track Changes for {0}, since it has been enabled to"
42 | " maintain Audit Trail"
43 | ).format(_(self.doc_type))
44 | )
45 |
--------------------------------------------------------------------------------
/india_compliance/public/js/new_gst_category_notification.js:
--------------------------------------------------------------------------------
1 | $(document).on("app_ready", async function () {
2 | if (!frappe.boot.needs_new_gst_category_notification) return;
3 |
4 | // let other processes finish
5 | await new Promise(resolve => setTimeout(resolve, 700));
6 | const d = frappe.msgprint({
7 | title: __("New GST Category Introduced"),
8 | indicator: "orange",
9 | message: __(
10 | `Dear India Compliance User,
11 |
12 |
13 | We would like to inform you about an important update regarding the GST category for Input Service Distributors (ISD).
14 |
15 |
16 | Previously, ISD was categorized under Registered Regular in our system. However, we have now introduced a dedicated GST category Input Service Distributor specifically for Input Service Distributors.
17 |
18 |
19 | Action Required:
20 |
21 | If you have been using the ISD under the Registered Regular GST category, please update your records to reflect the new Input Service Distributor category.
22 | `
23 | ),
24 | });
25 |
26 | d.onhide = () => {
27 | frappe.xcall(
28 | "india_compliance.gst_india.utils.disable_new_gst_category_notification"
29 | );
30 | };
31 | });
32 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_reconciliation_status.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull
3 |
4 |
5 | def execute():
6 | PI = frappe.qb.DocType("Purchase Invoice")
7 | PI_ITEM = frappe.qb.DocType("Purchase Invoice Item")
8 | BOE = frappe.qb.DocType("Bill of Entry")
9 |
10 | (
11 | frappe.qb.update(PI)
12 | .set(PI.reconciliation_status, "Not Applicable")
13 | .join(PI_ITEM)
14 | .on(PI.name == PI_ITEM.parent)
15 | .where(PI.docstatus == 1)
16 | .where(
17 | (IfNull(PI.supplier_gstin, "") == "")
18 | | (
19 | IfNull(PI.gst_category, "").isin(
20 | ["Registered Composition", "Unregistered", "Overseas"]
21 | )
22 | )
23 | | (IfNull(PI.supplier_gstin, "") == PI.company_gstin)
24 | | (IfNull(PI.is_opening, "") == "Yes")
25 | | (PI_ITEM.gst_treatment == "Non-GST")
26 | )
27 | .run()
28 | )
29 |
30 | (
31 | frappe.qb.update(PI)
32 | .set(PI.reconciliation_status, "Unreconciled")
33 | .where(PI.docstatus == 1)
34 | .where(IfNull(PI.reconciliation_status, "") == "")
35 | .run()
36 | )
37 |
38 | (
39 | frappe.qb.update(BOE)
40 | .set(BOE.reconciliation_status, "Unreconciled")
41 | .where(BOE.docstatus == 1)
42 | .run()
43 | )
44 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/invoice_history_table.html:
--------------------------------------------------------------------------------
1 | {% if data_array %}
2 |
3 |
4 |
5 |
6 | Name
7 | Posting Date
8 | Credits
9 | Grand Total
10 |
11 |
12 |
13 |
14 | {% for data in data_array %}
15 |
16 | {{ data.name }}
17 | {{ data.posting_date }}
18 | {{ data.credits }}
19 | {{ data.grand_total }}
20 |
21 |
25 | Get Invoice
26 |
27 |
28 |
29 | {% endfor %}
30 |
31 |
32 |
33 | {% else %}
34 |
35 | No invoices found!
36 |
37 | {% endif %}
38 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/merge_utgst_account_into_sgst_account.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | import frappe
4 |
5 | DOCTYPE = "GST Account"
6 |
7 |
8 | def execute():
9 | if not frappe.db.has_column(DOCTYPE, "utgst_account"):
10 | return
11 |
12 | gst_accounts = frappe.get_all(
13 | DOCTYPE,
14 | filters={"parent": "GST Settings", "utgst_account": ("is", "set")},
15 | fields=(
16 | "name",
17 | "sgst_account",
18 | "utgst_account",
19 | ),
20 | )
21 |
22 | if not gst_accounts:
23 | return
24 |
25 | values_to_set = {"utgst_account": ""}
26 |
27 | for row in gst_accounts:
28 | if not row.sgst_account:
29 | # SGST account was set as not mandatory by user?
30 | frappe.db.set_value(
31 | DOCTYPE,
32 | row.name,
33 | {"sgst_account": row.utgst_account, **values_to_set},
34 | )
35 | return
36 |
37 | frappe.rename_doc(
38 | "Account",
39 | row.utgst_account,
40 | row.sgst_account,
41 | merge=1,
42 | force=1,
43 | )
44 |
45 | frappe.db.set_value(DOCTYPE, row.name, values_to_set)
46 |
47 | click.secho(
48 | "The UTGST Accounts set in your GST Settings have been merged into the"
49 | " corresponding SGST / UTGST Accounts.\n",
50 | fg="yellow",
51 | )
52 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/item.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.doctype.gst_hsn_code.gst_hsn_code import (
4 | validate_hsn_code as _validate_hsn_code,
5 | )
6 |
7 |
8 | def validate(doc, method=None):
9 | update_hsn_code(doc)
10 | validate_hsn_code(doc)
11 | set_taxes_from_hsn_code(doc)
12 |
13 |
14 | def update_hsn_code(doc):
15 | """
16 | Update HSN Code from Fee Category (education), Healthcare Services (healthcare)
17 | """
18 | if not frappe.flags.cross_app_hsn_code:
19 | return
20 |
21 | doc.gst_hsn_code = frappe.flags.cross_app_hsn_code
22 | del frappe.flags.cross_app_hsn_code
23 |
24 |
25 | def validate_hsn_code(doc):
26 | # HSN Code is being validated only for sales items
27 | if not doc.is_sales_item:
28 | return
29 |
30 | _validate_hsn_code(doc.gst_hsn_code)
31 |
32 |
33 | def set_taxes_from_hsn_code(doc):
34 | if doc.taxes or not doc.gst_hsn_code:
35 | return
36 |
37 | hsn_doc = frappe.get_doc("GST HSN Code", doc.gst_hsn_code)
38 |
39 | for tax in hsn_doc.taxes:
40 | doc.append(
41 | "taxes",
42 | {
43 | "item_tax_template": tax.item_tax_template,
44 | "tax_category": tax.tax_category,
45 | "valid_from": tax.valid_from,
46 | "minimum_net_rate": tax.minimum_net_rate,
47 | "maximum_net_rate": tax.maximum_net_rate,
48 | },
49 | )
50 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/setup.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.audit_trail.constants.custom_fields import CUSTOM_FIELDS
4 | from india_compliance.audit_trail.utils import (
5 | get_audit_trail_doctypes,
6 | is_audit_trail_enabled,
7 | )
8 | from india_compliance.utils.custom_fields import get_custom_fields_creator
9 |
10 | _create_custom_fields = get_custom_fields_creator("Audit Trail")
11 |
12 |
13 | # Hooks
14 |
15 |
16 | def setup_fixtures():
17 | create_custom_fields()
18 | create_property_setters_for_versioning()
19 |
20 |
21 | def create_custom_fields():
22 | _create_custom_fields(CUSTOM_FIELDS)
23 |
24 |
25 | def create_property_setters_for_versioning():
26 | for doctype in get_audit_trail_doctypes():
27 | property_setter_data = {
28 | "doctype_or_field": "DocType",
29 | "doc_type": doctype,
30 | "property": "track_changes",
31 | "value": "1",
32 | "property_type": "Check",
33 | "is_system_generated": 1,
34 | }
35 |
36 | if frappe.db.exists("Property Setter", property_setter_data):
37 | continue
38 |
39 | property_setter = frappe.new_doc("Property Setter")
40 | property_setter.update(property_setter_data)
41 | property_setter.flags.ignore_permissions = True
42 | property_setter.insert()
43 |
44 |
45 | def after_migrate():
46 | if is_audit_trail_enabled():
47 | create_property_setters_for_versioning()
48 |
--------------------------------------------------------------------------------
/india_compliance/public/js/quick_info_popover.js:
--------------------------------------------------------------------------------
1 | frappe.provide("india_compliance");
2 |
3 | india_compliance.quick_info_popover = class QuickInfoPopover {
4 | constructor(frm, field_dict) {
5 | /**
6 | * Setup tooltip for fields to show details
7 | * @param {Object} frm Form object
8 | * @param {Object} field_dict Dictionary of fields with info to show
9 | */
10 | this.frm = frm;
11 | this.field_dict = field_dict;
12 | this.make();
13 | }
14 | make() {
15 | this.create_info_popover();
16 | }
17 | create_info_popover() {
18 | if (!this.field_dict) return;
19 |
20 | for (const [field, info] of Object.entries(this.field_dict)) {
21 | this.create_info_icon(field);
22 |
23 | if (!this.info_btn) return;
24 |
25 | this.info_btn.popover({
26 | trigger: "hover",
27 | placement: "top",
28 | content: () => this.get_content_html(field, info),
29 | html: true,
30 | });
31 | }
32 | }
33 | create_info_icon(field) {
34 | let field_area = this.frm.get_field(field).$wrapper.find(".clearfix");
35 | this.info_btn = $(` `).appendTo(field_area);
36 | }
37 | get_content_html(field, info) {
38 | let field_lable = frappe.meta.get_label(this.frm.doctype, field);
39 |
40 | return `
41 |
42 |
43 |
${__(field_lable)}
44 |
45 |
${info}
46 |
47 | `;
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/set_gst_tax_type.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder import Case
3 |
4 | from india_compliance.gst_india.utils import get_gst_account_gst_tax_type_map
5 |
6 | TAX_DOCTYPES = [
7 | "Sales Taxes and Charges",
8 | "Purchase Taxes and Charges",
9 | "Advance Taxes and Charges",
10 | ]
11 |
12 |
13 | def execute():
14 | gst_account_tax_type_map = get_gst_account_gst_tax_type_map()
15 |
16 | if not gst_account_tax_type_map:
17 | return
18 |
19 | gst_accounts_by_tax_type = {}
20 | for account, tax_type in gst_account_tax_type_map.items():
21 | gst_accounts_by_tax_type.setdefault(tax_type, []).append(account)
22 |
23 | for tax_doctype in TAX_DOCTYPES:
24 | update_documents(tax_doctype, gst_accounts_by_tax_type)
25 |
26 |
27 | def update_documents(taxes_doctype, gst_accounts_by_tax_type):
28 | taxes_doctype = frappe.qb.DocType(taxes_doctype)
29 |
30 | update_query = frappe.qb.update(taxes_doctype).where(
31 | taxes_doctype.parenttype.notin(
32 | ["Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]
33 | )
34 | )
35 |
36 | conditions = Case()
37 |
38 | for gst_tax_account, gst_tax_name in gst_accounts_by_tax_type.items():
39 | conditions = conditions.when(
40 | taxes_doctype.account_head.isin(gst_tax_name), gst_tax_account
41 | )
42 |
43 | conditions = conditions.else_(None)
44 |
45 | update_query.set(taxes_doctype.gst_tax_type, conditions).run()
46 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/delivery_note.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.overrides.sales_invoice import (
4 | is_e_waybill_applicable,
5 | is_shipping_address_in_india,
6 | update_dashboard_with_gst_logs,
7 | validate_port_address,
8 | )
9 | from india_compliance.gst_india.overrides.transaction import (
10 | validate_transaction,
11 | )
12 | from india_compliance.gst_india.utils import is_api_enabled
13 | from india_compliance.gst_india.utils.e_waybill import get_e_waybill_info
14 |
15 |
16 | def onload(doc, method=None):
17 | if not doc.get("ewaybill"):
18 | if doc.gst_category == "Overseas" and is_e_waybill_applicable(doc):
19 |
20 | doc.set_onload(
21 | "shipping_address_in_india", is_shipping_address_in_india(doc)
22 | )
23 | return
24 |
25 | gst_settings = frappe.get_cached_doc("GST Settings")
26 |
27 | if (
28 | is_api_enabled(gst_settings)
29 | and gst_settings.enable_e_waybill
30 | and (
31 | gst_settings.enable_e_waybill_from_dn or gst_settings.auto_cancel_e_waybill
32 | )
33 | and (e_waybill_info := get_e_waybill_info(doc))
34 | ):
35 | doc.set_onload("e_waybill_info", e_waybill_info)
36 |
37 |
38 | def validate(doc, method=None):
39 | if validate_transaction(doc) is False:
40 | return
41 |
42 | validate_port_address(doc)
43 |
44 |
45 | def get_dashboard_data(data):
46 | return update_dashboard_with_gst_logs(
47 | "Delivery Note", data, "e-Waybill Log", "Integration Request"
48 | )
49 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/services/AccountService.js:
--------------------------------------------------------------------------------
1 | export async function get_details(type) {
2 | return india_compliance.gst_api.call(`account.get_${type}_details`, {
3 | method: "GET",
4 | with_api_secret: true,
5 | });
6 | }
7 |
8 | export async function update_billing_details(new_billing_details) {
9 | return india_compliance.gst_api.call("account.update_billing_details", {
10 | method: "POST",
11 | body: { new_billing_details },
12 | with_api_secret: true,
13 | });
14 | }
15 |
16 | export async function create_order(credits, amount) {
17 | return india_compliance.gst_api.call("account.create_order", {
18 | method: "POST",
19 | body: { credits, amount },
20 | with_api_secret: true,
21 | });
22 | }
23 |
24 | export async function verify_payment(orderId) {
25 | return india_compliance.gst_api.call("account.verify_payment", {
26 | method: "POST",
27 | body: { order_id: orderId },
28 | with_api_secret: true,
29 | });
30 | }
31 |
32 | export async function get_invoice_history(from_date, to_date) {
33 | return india_compliance.gst_api.call("account.get_invoice_history", {
34 | method: "POST",
35 | body: { from_date, to_date },
36 | with_api_secret: true,
37 | });
38 | }
39 |
40 | export async function send_invoice_email(invoice_name, email) {
41 | return india_compliance.gst_api.call("account.send_invoice_email", {
42 | method: "POST",
43 | body: { invoice_name, email },
44 | with_api_secret: true,
45 | });
46 | }
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/set_gst_category.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.utils.custom_fields import delete_old_fields
4 |
5 |
6 | def execute():
7 | invoice_type_gst_category_map = {
8 | "Regular": "Registered Regular",
9 | "Export": "Overseas",
10 | "SEZ": "SEZ",
11 | "Deemed Export": "Deemed Export",
12 | }
13 |
14 | doctypes = ("Sales Invoice", "Purchase Invoice")
15 | for doctype in doctypes:
16 | if not frappe.db.exists(
17 | "Custom Field", {"dt": doctype, "fieldname": "invoice_type"}
18 | ):
19 | continue
20 |
21 | for invoice_type, gst_category in invoice_type_gst_category_map.items():
22 | frappe.db.set_value(
23 | doctype,
24 | {"gst_category": ("in", (None, "")), "invoice_type": invoice_type},
25 | "gst_category",
26 | gst_category,
27 | )
28 |
29 | delete_old_fields("invoice_type", doctypes)
30 |
31 | if "eligibility_for_itc" not in frappe.db.get_table_columns("Purchase Invoice"):
32 | return
33 |
34 | # update eligibility_for_itc with new options
35 | for old_value, new_value in {
36 | "ineligible": "Ineligible",
37 | "input service": "Input Service Distributor",
38 | "capital goods": "Import Of Goods",
39 | "input": "All Other ITC",
40 | }.items():
41 | frappe.db.set_value(
42 | "Purchase Invoice",
43 | {"eligibility_for_itc": old_value},
44 | "eligibility_for_itc",
45 | new_value,
46 | )
47 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_inward_supply_item/gst_inward_supply_item.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "creation": "2022-04-12 17:40:41.914298",
4 | "doctype": "DocType",
5 | "editable_grid": 1,
6 | "engine": "InnoDB",
7 | "field_order": [
8 | "item_number",
9 | "taxable_value",
10 | "rate",
11 | "igst",
12 | "cgst",
13 | "sgst",
14 | "cess"
15 | ],
16 | "fields": [
17 | {
18 | "fieldname": "item_number",
19 | "fieldtype": "Int",
20 | "label": "Item Number"
21 | },
22 | {
23 | "fieldname": "taxable_value",
24 | "fieldtype": "Float",
25 | "in_list_view": 1,
26 | "label": "Taxable Value"
27 | },
28 | {
29 | "fieldname": "rate",
30 | "fieldtype": "Float",
31 | "in_list_view": 1,
32 | "label": "Tax Rate"
33 | },
34 | {
35 | "fieldname": "igst",
36 | "fieldtype": "Float",
37 | "in_list_view": 1,
38 | "label": "IGST Amount"
39 | },
40 | {
41 | "fieldname": "cgst",
42 | "fieldtype": "Float",
43 | "in_list_view": 1,
44 | "label": "CGST Amount"
45 | },
46 | {
47 | "fieldname": "sgst",
48 | "fieldtype": "Float",
49 | "in_list_view": 1,
50 | "label": "SGST Amount"
51 | },
52 | {
53 | "fieldname": "cess",
54 | "fieldtype": "Float",
55 | "label": "CESS Amount"
56 | }
57 | ],
58 | "index_web_pages_for_search": 1,
59 | "istable": 1,
60 | "links": [],
61 | "modified": "2024-03-29 11:54:42.857545",
62 | "modified_by": "Administrator",
63 | "module": "GST India",
64 | "name": "GST Inward Supply Item",
65 | "owner": "Administrator",
66 | "permissions": [],
67 | "sort_field": "creation",
68 | "sort_order": "DESC",
69 | "states": []
70 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstr_action/gstr_action.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2024-09-09 17:43:22.979394",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "request_type",
10 | "request_id",
11 | "token",
12 | "status",
13 | "creation_time",
14 | "integration_request"
15 | ],
16 | "fields": [
17 | {
18 | "fieldname": "request_type",
19 | "fieldtype": "Data",
20 | "in_list_view": 1,
21 | "label": "Request Type"
22 | },
23 | {
24 | "fieldname": "token",
25 | "fieldtype": "Data",
26 | "hidden": 1,
27 | "label": "Token"
28 | },
29 | {
30 | "fieldname": "status",
31 | "fieldtype": "Data",
32 | "in_list_view": 1,
33 | "label": "Status"
34 | },
35 | {
36 | "fieldname": "creation_time",
37 | "fieldtype": "Datetime",
38 | "in_list_view": 1,
39 | "label": "Creation Time"
40 | },
41 | {
42 | "fieldname": "integration_request",
43 | "fieldtype": "Link",
44 | "in_list_view": 1,
45 | "label": "Integration Request",
46 | "options": "Integration Request",
47 | "read_only": 1
48 | },
49 | {
50 | "fieldname": "request_id",
51 | "fieldtype": "Data",
52 | "hidden": 1,
53 | "label": "Request id"
54 | }
55 | ],
56 | "index_web_pages_for_search": 1,
57 | "istable": 1,
58 | "links": [],
59 | "modified": "2025-01-22 16:33:57.014368",
60 | "modified_by": "Administrator",
61 | "module": "GST India",
62 | "name": "GSTR Action",
63 | "owner": "Administrator",
64 | "permissions": [],
65 | "sort_field": "creation",
66 | "sort_order": "DESC",
67 | "states": []
68 | }
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gstin/test_gstin.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Resilient Tech and Contributors
2 | # See license.txt
3 | import responses
4 | from responses import matchers
5 |
6 | from frappe.tests import IntegrationTestCase, change_settings
7 |
8 | from india_compliance.gst_india.doctype.gstin.gstin import validate_gst_transporter_id
9 |
10 | TEST_GSTIN = "24AANFA2641L1ZK"
11 |
12 | TRANSPORTER_ID_API_RESPONSE = {
13 | "success": True,
14 | "message": "Transporter details are fetched successfully",
15 | "result": {
16 | "transin": TEST_GSTIN,
17 | "tradeName": "_Test Transporter ID Comapany",
18 | "legalName": "_Test Transporter ID Comapany",
19 | "address1": "address 1",
20 | "address2": "address 2",
21 | "stateCode": "24",
22 | "pinCode": "390020",
23 | },
24 | }
25 |
26 |
27 | class TestGSTIN(IntegrationTestCase):
28 | @classmethod
29 | def setUpClass(cls):
30 | super().setUpClass()
31 |
32 | @responses.activate
33 | @change_settings("GST Settings", {"validate_gstin_status": 1, "sandbox_mode": 0})
34 | def test_validate_gst_transporter_id(self):
35 | self.mock_get_transporter_details_response()
36 |
37 | validate_gst_transporter_id(TEST_GSTIN)
38 |
39 | def mock_get_transporter_details_response(self):
40 | url = "https://asp.resilient.tech/ewb/Master/GetTransporterDetails"
41 |
42 | responses.add(
43 | responses.GET,
44 | url,
45 | json=TRANSPORTER_ID_API_RESPONSE,
46 | match=[matchers.query_param_matcher({"trn_no": TEST_GSTIN})],
47 | status=200,
48 | )
49 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/pan/pan.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "autoname": "field:pan",
4 | "creation": "2024-07-31 13:10:35.277697",
5 | "doctype": "DocType",
6 | "engine": "InnoDB",
7 | "field_order": [
8 | "pan",
9 | "pan_status",
10 | "column_break_hzzp",
11 | "last_updated_on"
12 | ],
13 | "fields": [
14 | {
15 | "fieldname": "pan",
16 | "fieldtype": "Data",
17 | "in_list_view": 1,
18 | "label": "Pan",
19 | "reqd": 1,
20 | "unique": 1
21 | },
22 | {
23 | "fieldname": "pan_status",
24 | "fieldtype": "Data",
25 | "in_list_view": 1,
26 | "in_standard_filter": 1,
27 | "label": "Pan Status"
28 | },
29 | {
30 | "fieldname": "last_updated_on",
31 | "fieldtype": "Datetime",
32 | "label": "Last Updated On"
33 | },
34 | {
35 | "fieldname": "column_break_hzzp",
36 | "fieldtype": "Column Break"
37 | }
38 | ],
39 | "in_create": 1,
40 | "index_web_pages_for_search": 1,
41 | "links": [],
42 | "modified": "2024-08-08 14:08:25.490761",
43 | "modified_by": "Administrator",
44 | "module": "GST India",
45 | "name": "PAN",
46 | "naming_rule": "By fieldname",
47 | "owner": "Administrator",
48 | "permissions": [
49 | {
50 | "delete": 1,
51 | "export": 1,
52 | "read": 1,
53 | "report": 1,
54 | "role": "System Manager",
55 | "share": 1
56 | },
57 | {
58 | "export": 1,
59 | "read": 1,
60 | "report": 1,
61 | "role": "Accounts Manager",
62 | "share": 1
63 | },
64 | {
65 | "export": 1,
66 | "read": 1,
67 | "report": 1,
68 | "role": "Accounts User",
69 | "share": 1
70 | }
71 | ],
72 | "sort_field": "creation",
73 | "sort_order": "DESC",
74 | "states": []
75 | }
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/property_setter.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe import _
3 | from frappe.utils import cint
4 |
5 | from india_compliance.audit_trail.utils import (
6 | get_audit_trail_doctypes,
7 | is_audit_trail_enabled,
8 | )
9 |
10 |
11 | def validate(doc, method=None):
12 | flags = frappe.local.flags
13 |
14 | if flags.in_install or flags.in_migrate or not is_audit_trail_enabled():
15 | return
16 |
17 | is_protected = is_protected_property_setter(doc)
18 | if doc.is_new() and (not is_protected or cint(doc.value) == 1):
19 | return
20 |
21 | if is_protected:
22 | throw_cannot_change_property_error(doc)
23 |
24 | old_doc = doc.get_doc_before_save()
25 | if is_protected_property_setter(old_doc):
26 | throw_cannot_change_property_error(old_doc)
27 |
28 |
29 | def on_trash(doc, method=None):
30 | flags = frappe.local.flags
31 |
32 | if (
33 | flags.in_install
34 | or flags.in_migrate
35 | or not is_audit_trail_enabled()
36 | or not is_protected_property_setter(doc)
37 | ):
38 | return
39 |
40 | throw_cannot_change_property_error(doc)
41 |
42 |
43 | def throw_cannot_change_property_error(doc):
44 | frappe.throw(
45 | _(
46 | "Cannot change the Track Changes property for {0}, since it has been"
47 | " enabled to maintain Audit Trail"
48 | ).format(_(doc.doc_type))
49 | )
50 |
51 |
52 | def is_protected_property_setter(doc):
53 | return (
54 | doc.doctype_or_field == "DocType"
55 | and doc.property == "track_changes"
56 | and doc.doc_type in get_audit_trail_doctypes()
57 | )
58 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/utils/api.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def enqueue_integration_request(**kwargs):
5 | frappe.enqueue(
6 | "india_compliance.gst_india.utils.api.create_integration_request",
7 | **kwargs,
8 | )
9 |
10 |
11 | def create_integration_request(
12 | url=None,
13 | request_id=None,
14 | request_headers=None,
15 | data=None,
16 | output=None,
17 | error=None,
18 | reference_doctype=None,
19 | reference_name=None,
20 | update_gstr_action=False,
21 | ):
22 | doc = frappe.get_doc(
23 | {
24 | "doctype": "Integration Request",
25 | "integration_request_service": "India Compliance API",
26 | "request_id": request_id,
27 | "url": url,
28 | "request_headers": pretty_json(request_headers),
29 | "data": pretty_json(data),
30 | "output": pretty_json(output),
31 | "error": pretty_json(error),
32 | "status": "Failed" if error else "Completed",
33 | "reference_doctype": reference_doctype,
34 | "reference_docname": reference_name,
35 | }
36 | )
37 | doc.insert(ignore_permissions=True, ignore_links=True)
38 |
39 | if update_gstr_action:
40 | link_integration_request(request_id, doc.name)
41 |
42 |
43 | def link_integration_request(request_id, doc_name):
44 | frappe.db.set_value(
45 | "GSTR Action", {"request_id": request_id}, {"integration_request": doc_name}
46 | )
47 |
48 |
49 | def pretty_json(obj):
50 | if not obj:
51 | return ""
52 |
53 | if isinstance(obj, str):
54 | return obj
55 |
56 | return frappe.as_json(obj, indent=4)
57 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/client_scripts/journal_entry.js:
--------------------------------------------------------------------------------
1 | frappe.ui.form.on("Journal Entry", {
2 | onload: (frm) => set_gstin_options(frm, frm.is_new()),
3 | company: (frm) => set_gstin_options(frm, true),
4 | });
5 |
6 | async function set_gstin_options(frm, set_value) {
7 | const company = frm.doc.company;
8 | if (!company) return;
9 |
10 | const options = await india_compliance.get_gstin_options(company);
11 | frm.get_field("company_gstin").set_data(options);
12 |
13 | if (set_value)
14 | frm.set_value("company_gstin", options.length === 1 ? options[0] : "");
15 | }
16 |
17 | frappe.ui.form.on("Journal Entry Account", {
18 | account: toggle_gstin_for_journal_entry,
19 | accounts_remove: toggle_gstin_for_journal_entry,
20 | });
21 |
22 | function toggle_gstin_for_journal_entry(frm) {
23 | toggle_company_gstin(frm, "accounts", "account");
24 | }
25 |
26 | async function toggle_company_gstin(frm, taxes_table, account_head) {
27 | _toggle_company_gstin(frm, await contains_gst_account(frm, taxes_table, account_head));
28 | }
29 |
30 | async function contains_gst_account(frm, taxes_table, account_field) {
31 | if (!frm.gst_accounts || frm.company !== frm.doc.company) {
32 | frm.gst_accounts = await india_compliance.get_account_options(frm.doc.company);
33 | frm.company = frm.doc.company;
34 | }
35 |
36 | return frm.doc[taxes_table].some(row => frm.gst_accounts.includes(row[account_field]));
37 | }
38 |
39 | function _toggle_company_gstin(frm, reqd) {
40 | if (frm.get_field("company_gstin").df.reqd !== reqd) {
41 | frm.set_df_property("company_gstin", "reqd", reqd);
42 | frm.refresh_field("company_gstin");
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_uom_map/gst_uom_map.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "creation": "2022-11-15 19:15:06.551557",
4 | "default_view": "List",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "uom",
10 | "gst_uom"
11 | ],
12 | "fields": [
13 | {
14 | "fieldname": "uom",
15 | "fieldtype": "Link",
16 | "in_list_view": 1,
17 | "label": "UOM",
18 | "options": "UOM",
19 | "reqd": 1,
20 | "unique": 1
21 | },
22 | {
23 | "fieldname": "gst_uom",
24 | "fieldtype": "Autocomplete",
25 | "in_list_view": 1,
26 | "label": "GST UOM",
27 | "options": "\nBAG (Bags)\nBAL (Bale)\nBDL (Bundles)\nBKL (Buckles)\nBOU (Billion of Units)\nBOX (Box)\nBTL (Bottles)\nBUN (Bunches)\nCAN (Cans)\nCBM (Cubic Meters)\nCCM (Cubic Centimeters)\nCMS (Centimeters)\nCTN (Cartons)\nDOZ (Dozens)\nDRM (Drums)\nGGK (Great Gross)\nGMS (Grammes)\nGRS (Gross)\nGYD (Gross Yards)\nKGS (Kilograms)\nKLR (Kilolitre)\nKME (Kilometre)\nLTR (Litres)\nMLT (Mililitre)\nMTR (Meters)\nMTS (Metric Ton)\nNOS (Numbers)\nOTH (Others)\nPAC (Packs)\nPCS (Pieces)\nPRS (Pairs)\nQTL (Quintal)\nROL (Rolls)\nSET (Sets)\nSQF (Square Feet)\nSQM (Square Meters)\nSQY (Square Yards)\nTBS (Tablets)\nTGM (Ten Gross)\nTHD (Thousands)\nTON (Tonnes)\nTUB (Tubes)\nUGS (US Gallons)\nUNT (Units)\nYDS (Yards)",
28 | "reqd": 1
29 | }
30 | ],
31 | "index_web_pages_for_search": 1,
32 | "istable": 1,
33 | "links": [],
34 | "modified": "2024-03-29 11:54:43.163793",
35 | "modified_by": "Administrator",
36 | "module": "GST India",
37 | "name": "GST UOM Map",
38 | "owner": "Administrator",
39 | "permissions": [],
40 | "sort_field": "creation",
41 | "sort_order": "DESC",
42 | "states": []
43 | }
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_gst_treatment_for_taxable_nil_transaction_item.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | DOCTYPES = ("Sales Invoice Item", "Purchase Invoice Item")
4 |
5 |
6 | def execute():
7 | update_taxable_items()
8 | update_nil_rated_items()
9 |
10 |
11 | def update_taxable_items():
12 | # Patch invoices where gst_treatment is Nil-Rated but tax is applied.
13 | # Cases where is_nil_exempt was checked but Item tax template was selected.
14 | for dt in DOCTYPES:
15 | doctype = frappe.qb.DocType(dt)
16 |
17 | (
18 | frappe.qb.update(doctype)
19 | .set(doctype.gst_treatment, "Taxable")
20 | .where(doctype.gst_treatment.notin(("Zero-Rated", "Taxable")))
21 | .where(
22 | (
23 | doctype.cgst_amount
24 | + doctype.igst_amount
25 | + doctype.sgst_amount
26 | + doctype.cess_amount
27 | )
28 | != 0
29 | )
30 | .run()
31 | )
32 |
33 |
34 | def update_nil_rated_items():
35 | # Patch invoices where Item Tax Template is Nil-Rated.
36 |
37 | nil_rated_templates = frappe.get_all(
38 | "Item Tax Template", filters={"gst_treatment": "Nil-Rated"}, pluck="name"
39 | )
40 |
41 | if not nil_rated_templates:
42 | return
43 |
44 | for dt in DOCTYPES:
45 | doctype = frappe.qb.DocType(dt)
46 |
47 | (
48 | frappe.qb.update(doctype)
49 | .set(doctype.gst_treatment, "Nil-Rated")
50 | .where(doctype.item_tax_template.isin(nil_rated_templates))
51 | .where(doctype.gst_treatment == "Taxable")
52 | .run()
53 | )
54 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/test_version.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import frappe
4 | from frappe.tests import IntegrationTestCase
5 |
6 | from india_compliance.gst_india.utils.tests import create_sales_invoice
7 |
8 |
9 | class TestVersion(IntegrationTestCase):
10 | def test_validate_version_where_audit_trail_enabled(self):
11 | # enable audit trail
12 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 1)
13 |
14 | doc = create_sales_invoice(do_not_submit=True)
15 | doc.items[0].qty = 2
16 | doc.save(ignore_version=False)
17 | doc.submit()
18 |
19 | version = frappe.get_doc(
20 | "Version", {"ref_doctype": doc.doctype, "docname": doc.name}
21 | )
22 |
23 | version.ref_doctype = "Address"
24 |
25 | self.assertRaisesRegex(
26 | frappe.ValidationError,
27 | re.compile(r"^(Cannot alter Versions of.*)"),
28 | version.save,
29 | )
30 |
31 | self.assertRaisesRegex(
32 | frappe.ValidationError,
33 | re.compile(r"^(Cannot alter Versions of.*)"),
34 | version.delete,
35 | )
36 |
37 | # disable audit trail
38 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 0)
39 |
40 | def test_validate_version_where_audit_trail_disabled(self):
41 | doc = create_sales_invoice(do_not_submit=True)
42 | doc.items[0].qty = 2
43 | doc.save(ignore_version=False)
44 | doc.submit()
45 |
46 | version = frappe.get_doc(
47 | "Version", {"ref_doctype": doc.doctype, "docname": doc.name}
48 | )
49 |
50 | version.ref_doctype = "Address"
51 |
52 | version.save()
53 | version.delete()
54 |
--------------------------------------------------------------------------------
/india_compliance/audit_trail/overrides/test_property_setter.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import frappe
4 | from frappe.tests import IntegrationTestCase
5 |
6 |
7 | class TestPropertySetter(IntegrationTestCase):
8 | def test_validate_property_setter_where_audit_trail_enabled_and_doc_is_protected(
9 | self,
10 | ):
11 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 1)
12 | frappe.db.delete(
13 | "Property Setter",
14 | {
15 | "doctype_or_field": "DocType",
16 | "doc_type": "Purchase Invoice",
17 | "property": "track_changes",
18 | },
19 | )
20 |
21 | doc = frappe.get_doc(
22 | {
23 | "doctype": "Property Setter",
24 | "doctype_or_field": "DocType",
25 | "doc_type": "Purchase Invoice",
26 | "property": "track_changes",
27 | "value": 1,
28 | },
29 | )
30 | doc.save()
31 | doc.value = 0
32 |
33 | self.assertRaisesRegex(
34 | frappe.ValidationError,
35 | re.compile(r"^(Cannot change the Track Changes property for*)"),
36 | doc.save,
37 | )
38 |
39 | self.assertRaisesRegex(
40 | frappe.ValidationError,
41 | re.compile(r"^(Cannot change the Track Changes property for*)"),
42 | doc.delete,
43 | )
44 | doc.reload()
45 | doc.doc_type = "Address"
46 | self.assertRaisesRegex(
47 | frappe.ValidationError,
48 | re.compile(r"^(Cannot change the Track Changes property for*)"),
49 | doc.save,
50 | )
51 | frappe.db.set_single_value("Accounts Settings", "enable_audit_trail", 0)
52 | doc.delete()
53 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/doctype/gst_hsn_code/gst_hsn_code.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "autoname": "field:hsn_code",
4 | "creation": "2017-06-21 10:48:56.422086",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": [
9 | "hsn_code",
10 | "description",
11 | "taxes"
12 | ],
13 | "fields": [
14 | {
15 | "fieldname": "hsn_code",
16 | "fieldtype": "Data",
17 | "in_list_view": 1,
18 | "label": "HSN Code",
19 | "reqd": 1,
20 | "unique": 1
21 | },
22 | {
23 | "fieldname": "description",
24 | "fieldtype": "Small Text",
25 | "in_list_view": 1,
26 | "label": "Description"
27 | },
28 | {
29 | "fieldname": "taxes",
30 | "fieldtype": "Table",
31 | "label": "Taxes",
32 | "options": "Item Tax"
33 | }
34 | ],
35 | "links": [],
36 | "modified": "2024-03-29 11:54:42.576237",
37 | "modified_by": "Administrator",
38 | "module": "GST India",
39 | "name": "GST HSN Code",
40 | "naming_rule": "By fieldname",
41 | "owner": "Administrator",
42 | "permissions": [
43 | {
44 | "read": 1,
45 | "role": "All"
46 | },
47 | {
48 | "create": 1,
49 | "read": 1,
50 | "role": "Accounts Manager",
51 | "write": 1
52 | },
53 | {
54 | "create": 1,
55 | "read": 1,
56 | "role": "Accounts User",
57 | "write": 1
58 | },
59 | {
60 | "create": 1,
61 | "read": 1,
62 | "role": "System Manager",
63 | "write": 1
64 | },
65 | {
66 | "create": 1,
67 | "read": 1,
68 | "role": "Item Manager",
69 | "write": 1
70 | },
71 | {
72 | "create": 1,
73 | "read": 1,
74 | "role": "Stock Manager",
75 | "write": 1
76 | }
77 | ],
78 | "quick_entry": 1,
79 | "search_fields": "hsn_code, description",
80 | "sort_field": "creation",
81 | "sort_order": "DESC",
82 | "states": [],
83 | "title_field": "hsn_code",
84 | "track_changes": 1
85 | }
--------------------------------------------------------------------------------
/india_compliance/patches/v14/set_correct_root_account_for_rcm.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.constants import GST_ACCOUNT_FIELDS
4 |
5 |
6 | def execute():
7 | settings = frappe.get_doc("GST Settings")
8 | company_accounts = get_company_accounts(settings)
9 |
10 | for accounts in company_accounts.values():
11 | if not accounts.get("Output") or not accounts.get("Purchase Reverse Charge"):
12 | continue
13 |
14 | rcm_accounts = get_asset_rcm_accounts(accounts)
15 | if not rcm_accounts:
16 | continue
17 |
18 | output_account = frappe.db.get_value(
19 | "Account",
20 | accounts["Output"].cgst_account,
21 | ["parent_account", "root_type"],
22 | as_dict=True,
23 | )
24 |
25 | if not output_account:
26 | continue
27 |
28 | # update reverse charge accounts
29 | frappe.db.set_value(
30 | "Account",
31 | {"name": ("in", rcm_accounts)},
32 | output_account,
33 | update_modified=False,
34 | )
35 |
36 |
37 | def get_company_accounts(settings):
38 | company_accounts = {}
39 | for row in settings.gst_accounts:
40 | company_accounts.setdefault(row.company, {})
41 | company_accounts[row.company][row.account_type] = row
42 |
43 | return company_accounts
44 |
45 |
46 | def get_asset_rcm_accounts(accounts):
47 | return frappe.get_all(
48 | "Account",
49 | filters={
50 | "root_type": "Asset",
51 | "name": (
52 | "in",
53 | [
54 | accounts["Purchase Reverse Charge"].get(field)
55 | for field in GST_ACCOUNT_FIELDS
56 | ],
57 | ),
58 | },
59 | pluck="name",
60 | )
61 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/components/TheFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
77 |
--------------------------------------------------------------------------------
/india_compliance/gst_india/overrides/purchase_receipt.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 | from india_compliance.gst_india.overrides.purchase_invoice import (
4 | set_ineligibility_reason,
5 | )
6 | from india_compliance.gst_india.overrides.sales_invoice import (
7 | update_dashboard_with_gst_logs,
8 | )
9 | from india_compliance.gst_india.overrides.transaction import (
10 | ignore_gst_validations,
11 | validate_mandatory_fields,
12 | validate_transaction,
13 | )
14 | from india_compliance.gst_india.utils import is_api_enabled
15 | from india_compliance.gst_india.utils.e_waybill import get_e_waybill_info
16 |
17 |
18 | def get_dashboard_data(data):
19 | return update_dashboard_with_gst_logs(
20 | "Purchase Receipt",
21 | data,
22 | "e-Waybill Log",
23 | "Integration Request",
24 | )
25 |
26 |
27 | def onload(doc, method=None):
28 | if ignore_gst_validations(doc):
29 | return
30 |
31 | if (
32 | validate_mandatory_fields(
33 | doc, ("company_gstin", "place_of_supply", "gst_category"), throw=False
34 | )
35 | is False
36 | ):
37 | return
38 |
39 | set_ineligibility_reason(doc, show_alert=False)
40 |
41 | # Load e-waybill info if applicable
42 | if not doc.get("ewaybill"):
43 | return
44 |
45 | gst_settings = frappe.get_cached_doc("GST Settings")
46 |
47 | if (
48 | is_api_enabled(gst_settings)
49 | and gst_settings.enable_e_waybill
50 | and (
51 | gst_settings.enable_e_waybill_from_pr or gst_settings.auto_cancel_e_waybill
52 | )
53 | and (e_waybill_info := get_e_waybill_info(doc))
54 | ):
55 | doc.set_onload("e_waybill_info", e_waybill_info)
56 |
57 |
58 | def validate(doc, method=None):
59 | if validate_transaction(doc) is False:
60 | return
61 |
62 | set_ineligibility_reason(doc)
63 |
--------------------------------------------------------------------------------
/india_compliance/patches/post_install/update_itc_classification_field.py:
--------------------------------------------------------------------------------
1 | import frappe
2 | from frappe.query_builder.functions import IfNull
3 |
4 | from india_compliance.utils.custom_fields import delete_old_fields
5 |
6 |
7 | def execute():
8 | patch_field_in_purchase_invoice()
9 | patch_journal_entry()
10 |
11 | delete_old_fields("eligibility_for_itc", "Purchase Invoice")
12 | delete_old_fields("reversal_type", "Journal Entry")
13 |
14 |
15 | def patch_field_in_purchase_invoice():
16 | if "eligibility_for_itc" not in frappe.db.get_table_columns("Purchase Invoice"):
17 | return
18 |
19 | doctype = frappe.qb.DocType("Purchase Invoice")
20 | depricated_eligibility_for_itc = (
21 | "Ineligible As Per Section 17(5)",
22 | "Ineligible Others",
23 | )
24 | (
25 | frappe.qb.update(doctype)
26 | .set(doctype.itc_classification, doctype.eligibility_for_itc)
27 | .where(doctype.eligibility_for_itc.notin(depricated_eligibility_for_itc))
28 | .run()
29 | )
30 | (
31 | frappe.qb.update(doctype)
32 | .set(doctype.itc_classification, "All Other ITC")
33 | .where(IfNull(doctype.itc_classification, "") == "")
34 | .run()
35 | )
36 | (
37 | frappe.qb.update(doctype)
38 | .set(doctype.ineligibility_reason, "Ineligible As Per Section 17(5)")
39 | .where(doctype.eligibility_for_itc.isin(depricated_eligibility_for_itc))
40 | .run()
41 | )
42 |
43 |
44 | def patch_journal_entry():
45 | if "reversal_type" not in frappe.db.get_table_columns("Journal Entry"):
46 | return
47 |
48 | doctype = frappe.qb.DocType("Journal Entry")
49 | (
50 | frappe.qb.update(doctype)
51 | .set(doctype.reversal_type, doctype.ineligibility_reason)
52 | .where(IfNull(doctype.reversal_type, "") != "")
53 | .run()
54 | )
55 |
--------------------------------------------------------------------------------
/india_compliance/public/js/india_compliance_account/services/AuthService.js:
--------------------------------------------------------------------------------
1 | export async function get_api_secret() {
2 | return call_server_method(
3 | "india_compliance.gst_india.page.india_compliance_account.get_api_secret"
4 | );
5 | }
6 |
7 | export async function set_api_secret(api_secret) {
8 | return call_server_method(
9 | "india_compliance.gst_india.page.india_compliance_account.set_api_secret",
10 | { api_secret }
11 | );
12 | }
13 |
14 | export function login(email) {
15 | return india_compliance.gst_api.call("auth/login", {
16 | body: { email },
17 | fail_silently: true,
18 | });
19 | }
20 |
21 | export function signup(email, gstin) {
22 | return india_compliance.gst_api.call("auth/signup", {
23 | body: { email, gstin },
24 | fail_silently: true,
25 | });
26 | }
27 |
28 | export function check_free_trial_eligibility(gstin) {
29 | return india_compliance.gst_api.call("auth/is_eligible_for_free_trial", {
30 | body: { gstin },
31 | fail_silently: true,
32 | });
33 | }
34 |
35 | export function get_session() {
36 | return call_server_method("india_compliance.gst_india.page.india_compliance_account.get_auth_session");
37 | }
38 |
39 | export function set_session(session) {
40 | call_server_method("india_compliance.gst_india.page.india_compliance_account.set_auth_session", {
41 | session,
42 | });
43 | }
44 |
45 | export function validate_session(session_id) {
46 | return india_compliance.gst_api.call("auth/validate_session", {
47 | body: { session_id },
48 | });
49 | }
50 |
51 | function call_server_method(method, args) {
52 | return frappe
53 | .call({
54 | method: method,
55 | args: args,
56 | silent: true,
57 | })
58 | .then((response) => response.message || null)
59 | .catch(() => null);
60 | }
61 |
--------------------------------------------------------------------------------