Merge branch 'develop' into sales-commission-payout

This commit is contained in:
Afshan
2021-10-18 11:16:16 +05:30
committed by GitHub
153 changed files with 2065 additions and 847 deletions

View File

@@ -1,6 +1,8 @@
[flake8]
ignore =
B007,
B009,
B010,
B950,
E101,
E111,
@@ -65,11 +67,6 @@ ignore =
E713,
E712,
enable-extensions =
M90
select =
M511
max-line-length = 200
exclude=.github/helper/semgrep_rules,test_*.py

View File

@@ -131,3 +131,21 @@ rules:
key `$X` is uselessly assigned twice. This could be a potential bug.
languages: [python]
severity: ERROR
- id: frappe-manual-commit
patterns:
- pattern: frappe.db.commit()
- pattern-not-inside: |
try:
...
except ...:
...
message: |
Manually commiting a transaction is highly discouraged. Read about the transaction model implemented by Frappe Framework before adding manual commits: https://frappeframework.com/docs/user/en/api/database#database-transaction-model If you think manual commit is required then add a comment explaining why and `// nosemgrep` on the same line.
paths:
exclude:
- "**/patches/**"
- "**/demo/**"
languages: [python]
severity: ERROR

32
.github/try-on-f-cloud-button.svg vendored Normal file
View File

@@ -0,0 +1,32 @@
<svg width="201" height="60" viewBox="0 0 201 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_dd)">
<rect x="4" y="2" width="193" height="52" rx="6" fill="#2490EF"/>
<path d="M28 22.2891H32.8786V35.5H36.2088V22.2891H41.0874V19.5H28V22.2891Z" fill="white"/>
<path d="M41.6982 35.5H45.0129V28.7109C45.0129 27.2344 46.0866 26.2188 47.5494 26.2188C48.0085 26.2188 48.6388 26.2969 48.95 26.3984V23.4453C48.6543 23.375 48.2419 23.3281 47.9074 23.3281C46.5691 23.3281 45.472 24.1094 45.0362 25.5938H44.9117V23.5H41.6982V35.5Z" fill="white"/>
<path d="M52.8331 40C55.2996 40 56.6068 38.7344 57.2837 36.7969L61.9289 23.5156L58.4197 23.5L55.9221 32.3125H55.7976L53.3233 23.5H49.8374L54.1247 35.8437L53.9302 36.3516C53.4944 37.4766 52.6619 37.5312 51.4947 37.1719L50.7478 39.6562C51.2224 39.8594 51.9927 40 52.8331 40Z" fill="white"/>
<path d="M73.6142 35.7344C77.2401 35.7344 79.4966 33.2422 79.4966 29.5469C79.4966 25.8281 77.2401 23.3438 73.6142 23.3438C69.9883 23.3438 67.7319 25.8281 67.7319 29.5469C67.7319 33.2422 69.9883 35.7344 73.6142 35.7344ZM73.6298 33.1562C71.9569 33.1562 71.101 31.6171 71.101 29.5233C71.101 27.4296 71.9569 25.8827 73.6298 25.8827C75.2715 25.8827 76.1274 27.4296 76.1274 29.5233C76.1274 31.6171 75.2715 33.1562 73.6298 33.1562Z" fill="white"/>
<path d="M84.7253 28.5625C84.7331 27.0156 85.6512 26.1094 86.9895 26.1094C88.3201 26.1094 89.1215 26.9844 89.1137 28.4531V35.5H92.4284V27.8594C92.4284 25.0625 90.7945 23.3438 88.3046 23.3438C86.5306 23.3438 85.2466 24.2187 84.7097 25.6172H84.5697V23.5H81.4106V35.5H84.7253V28.5625Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M102.429 19.5H113.429V22.3141H102.429V19.5ZM102.429 35.5V26.6794H112.699V29.4982H105.94V35.5H102.429Z" fill="white"/>
<path d="M131.584 24.9625C131.09 21.5057 128.345 19.5 124.785 19.5C120.589 19.5 117.429 22.463 117.429 27.4924C117.429 32.5142 120.55 35.4848 124.785 35.4848C128.604 35.4848 131.137 33.0916 131.584 30.1211L128.651 30.1059C128.282 31.9293 126.745 32.9549 124.824 32.9549C122.22 32.9549 120.354 31.0632 120.354 27.4924C120.354 23.9824 122.204 22.0299 124.832 22.0299C126.784 22.0299 128.314 23.1011 128.651 24.9625H131.584Z" fill="white"/>
<path d="M136.409 19.7124H133.571V35.2718H136.409V19.7124Z" fill="white"/>
<path d="M144.031 35.5001C147.56 35.5001 149.803 33.0917 149.803 29.483C149.803 25.8667 147.56 23.4507 144.031 23.4507C140.502 23.4507 138.259 25.8667 138.259 29.483C138.259 33.0917 140.502 35.5001 144.031 35.5001ZM144.047 33.2969C142.094 33.2969 141.137 31.6103 141.137 29.4754C141.137 27.3406 142.094 25.6312 144.047 25.6312C145.968 25.6312 146.925 27.3406 146.925 29.4754C146.925 31.6103 145.968 33.2969 144.047 33.2969Z" fill="white"/>
<path d="M159.338 30.3641C159.338 32.1419 158.028 33.0232 156.773 33.0232C155.409 33.0232 154.499 32.0887 154.499 30.6072V23.6025H151.66V31.0327C151.66 33.8361 153.307 35.4239 155.675 35.4239C157.479 35.4239 158.749 34.5046 159.298 33.1979H159.424V35.272H162.176V23.6025H159.338V30.3641Z" fill="white"/>
<path d="M169.014 35.4769C171.084 35.4769 172.017 34.2841 172.464 33.4332H172.637V35.2718H175.429V19.7124H172.582V25.532H172.464C172.033 24.6887 171.147 23.4503 169.022 23.4503C166.238 23.4503 164.05 25.5624 164.05 29.4522C164.05 33.2965 166.175 35.4769 169.014 35.4769ZM169.806 33.2205C167.931 33.2205 166.943 31.6251 166.943 29.437C166.943 27.2642 167.916 25.7067 169.806 25.7067C171.633 25.7067 172.637 27.173 172.637 29.437C172.637 31.701 171.617 33.2205 169.806 33.2205Z" fill="white"/>
</g>
<defs>
<filter id="filter0_dd" x="0" y="0" width="201" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.25"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.13 0"/>
<feBlend mode="normal" in2="effect1_dropShadow" result="effect2_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect2_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -21,9 +21,9 @@ repos:
hooks:
- id: flake8
additional_dependencies: [
'flake8-mutable',
'flake8-bugbear',
]
args: ['--select=M511', '--config', '.github/helper/.flake8_strict']
args: ['--config', '.github/helper/.flake8_strict']
exclude: ".*setup.py$"
- repo: https://github.com/timothycrosley/isort

View File

@@ -39,6 +39,12 @@ ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a
---
<div align="center">
<a href="https://frappecloud.com/deploy?apps=frappe,erpnext&source=erpnext_readme">
<img src=".github/try-on-f-cloud-button.svg" height="40">
</a>
</div>
### Containerized Installation
Use docker to deploy ERPNext in production or for development of [Frappe](https://github.com/frappe/frappe) apps. See https://github.com/frappe/frappe_docker for more details.

View File

@@ -24,7 +24,7 @@ context('Organizational Chart', () => {
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.type('Test Org Chart{downarrow}{enter}', { force: true })
.blur({ force: true });
});
});

View File

@@ -25,7 +25,7 @@ context('Organizational Chart Mobile', () => {
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.type('Test Org Chart{downarrow}{enter}', { force: true })
.blur({ force: true });
});
});

View File

@@ -8,6 +8,8 @@ from frappe import _, throw
from frappe.utils import cint, cstr
from frappe.utils.nestedset import NestedSet, get_ancestors_of, get_descendants_of
import erpnext
class RootNotEditable(frappe.ValidationError): pass
class BalanceMismatchError(frappe.ValidationError): pass
@@ -196,7 +198,7 @@ class Account(NestedSet):
"company": company,
# parent account's currency should be passed down to child account's curreny
# if it is None, it picks it up from default company currency, which might be unintended
"account_currency": self.account_currency,
"account_currency": erpnext.get_company_currency(company),
"parent_account": parent_acc_name_map[company]
})
@@ -207,8 +209,7 @@ class Account(NestedSet):
# update the parent company's value in child companies
doc = frappe.get_doc("Account", child_account)
parent_value_changed = False
for field in ['account_type', 'account_currency',
'freeze_account', 'balance_must_be']:
for field in ['account_type', 'freeze_account', 'balance_must_be']:
if doc.get(field) != self.get(field):
parent_value_changed = True
doc.set(field, self.get(field))

View File

@@ -12,7 +12,7 @@ from six import iteritems
from unidecode import unidecode
def create_charts(company, chart_template=None, existing_company=None, custom_chart=None):
def create_charts(company, chart_template=None, existing_company=None, custom_chart=None, from_coa_importer=None):
chart = custom_chart or get_chart(chart_template, existing_company)
if chart:
accounts = []
@@ -22,7 +22,7 @@ def create_charts(company, chart_template=None, existing_company=None, custom_ch
if root_account:
root_type = child.get("root_type")
if account_name not in ["account_number", "account_type",
if account_name not in ["account_name", "account_number", "account_type",
"root_type", "is_group", "tax_rate"]:
account_number = cstr(child.get("account_number")).strip()
@@ -35,7 +35,7 @@ def create_charts(company, chart_template=None, existing_company=None, custom_ch
account = frappe.get_doc({
"doctype": "Account",
"account_name": account_name,
"account_name": child.get('account_name') if from_coa_importer else account_name,
"company": company,
"parent_account": parent,
"is_group": is_group,
@@ -213,7 +213,7 @@ def validate_bank_account(coa, bank_account):
return (bank_account in accounts)
@frappe.whitelist()
def build_tree_from_json(chart_template, chart_data=None):
def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=False):
''' get chart template from its folder and parse the json to be rendered as tree '''
chart = chart_data or get_chart(chart_template)
@@ -226,9 +226,12 @@ def build_tree_from_json(chart_template, chart_data=None):
''' recursively called to form a parent-child based list of dict from chart template '''
for account_name, child in iteritems(children):
account = {}
if account_name in ["account_number", "account_type",\
if account_name in ["account_name", "account_number", "account_type",\
"root_type", "is_group", "tax_rate"]: continue
if from_coa_importer:
account_name = child['account_name']
account['parent_account'] = parent
account['expandable'] = True if identify_is_group(child) else False
account['value'] = (cstr(child.get('account_number')).strip() + ' - ' + account_name) \

View File

@@ -174,7 +174,7 @@
"default": "0",
"fieldname": "automatically_fetch_payment_terms",
"fieldtype": "Check",
"label": "Automatically Fetch Payment Terms"
"label": "Automatically Fetch Payment Terms from Order"
},
{
"description": "The percentage you are allowed to bill more against the amount ordered. For example, if the order value is $100 for an item and tolerance is set as 10%, then you are allowed to bill up to $110 ",
@@ -282,7 +282,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-08-19 11:17:38.788054",
"modified": "2021-10-11 17:42:36.427699",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -69,7 +69,7 @@ def import_coa(file_name, company):
frappe.local.flags.ignore_root_company_validation = True
forest = build_forest(data)
create_charts(company, custom_chart=forest)
create_charts(company, custom_chart=forest, from_coa_importer=True)
# trigger on_update for company to reset default accounts
set_default_accounts(company)
@@ -148,7 +148,7 @@ def get_coa(doctype, parent, is_root=False, file_name=None, for_validate=0):
if not for_validate:
forest = build_forest(data)
accounts = build_tree_from_json("", chart_data=forest) # returns a list of dict in a tree render-able form
accounts = build_tree_from_json("", chart_data=forest, from_coa_importer=True) # returns a list of dict in a tree render-able form
# filter out to show data for the selected node only
accounts = [d for d in accounts if d['parent_account']==parent]
@@ -212,11 +212,14 @@ def build_forest(data):
if not account_name:
error_messages.append("Row {0}: Please enter Account Name".format(line_no))
name = account_name
if account_number:
account_number = cstr(account_number).strip()
account_name = "{} - {}".format(account_number, account_name)
charts_map[account_name] = {}
charts_map[account_name]['account_name'] = name
if account_number: charts_map[account_name]["account_number"] = account_number
if cint(is_group) == 1: charts_map[account_name]["is_group"] = is_group
if account_type: charts_map[account_name]["account_type"] = account_type
if root_type: charts_map[account_name]["root_type"] = root_type

View File

@@ -16,7 +16,7 @@ class LoyaltyPointEntry(Document):
def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=None):
if not expiry_date:
date = today()
expiry_date = today()
return frappe.db.sql('''
select name, loyalty_points, expiry_date, loyalty_program_tier, invoice_type, invoice

View File

@@ -505,12 +505,13 @@ class PaymentEntry(AccountsController):
def validate_received_amount(self):
if self.paid_from_account_currency == self.paid_to_account_currency:
if self.paid_amount != self.received_amount:
if self.paid_amount < self.received_amount:
frappe.throw(_("Received Amount cannot be greater than Paid Amount"))
def set_received_amount(self):
self.base_received_amount = self.base_paid_amount
if self.paid_from_account_currency == self.paid_to_account_currency:
if self.paid_from_account_currency == self.paid_to_account_currency \
and not self.payment_type == 'Internal Transfer':
self.received_amount = self.paid_amount
def set_amounts_after_tax(self):
@@ -712,10 +713,14 @@ class PaymentEntry(AccountsController):
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
for d in self.get("references"):
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
gle.update({
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name
"against_voucher": d.reference_name,
"cost_center": cost_center
})
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),

View File

@@ -52,21 +52,35 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
refresh() {
this.frm.disable_save();
this.frm.set_df_property('invoices', 'cannot_delete_rows', true);
this.frm.set_df_property('payments', 'cannot_delete_rows', true);
this.frm.set_df_property('allocation', 'cannot_delete_rows', true);
this.frm.set_df_property('invoices', 'cannot_add_rows', true);
this.frm.set_df_property('payments', 'cannot_add_rows', true);
this.frm.set_df_property('allocation', 'cannot_add_rows', true);
if (this.frm.doc.receivable_payable_account) {
this.frm.add_custom_button(__('Get Unreconciled Entries'), () =>
this.frm.trigger("get_unreconciled_entries")
);
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary');
}
if (this.frm.doc.invoices.length && this.frm.doc.payments.length) {
this.frm.add_custom_button(__('Allocate'), () =>
this.frm.trigger("allocate")
);
this.frm.change_custom_button_type('Allocate', null, 'primary');
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default');
}
if (this.frm.doc.allocation.length) {
this.frm.add_custom_button(__('Reconcile'), () =>
this.frm.trigger("reconcile")
);
this.frm.change_custom_button_type('Reconcile', null, 'primary');
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default');
this.frm.change_custom_button_type('Allocate', null, 'default');
}
}

View File

@@ -12,15 +12,16 @@
"receivable_payable_account",
"col_break1",
"from_invoice_date",
"to_invoice_date",
"minimum_invoice_amount",
"maximum_invoice_amount",
"invoice_limit",
"column_break_13",
"from_payment_date",
"to_payment_date",
"minimum_invoice_amount",
"minimum_payment_amount",
"column_break_11",
"to_invoice_date",
"to_payment_date",
"maximum_invoice_amount",
"maximum_payment_amount",
"column_break_13",
"invoice_limit",
"payment_limit",
"bank_cash_account",
"sec_break1",
@@ -79,6 +80,7 @@
},
{
"depends_on": "eval:(doc.payments).length || (doc.invoices).length",
"description": "If you need to reconcile particular transactions against each other, then please select accordingly. If not, all the transactions will be allocated in FIFO order.",
"fieldname": "sec_break1",
"fieldtype": "Section Break",
"label": "Unreconciled Entries"
@@ -163,6 +165,7 @@
"label": "Maximum Payment Amount"
},
{
"description": "System will fetch all the entries if limit value is zero.",
"fieldname": "payment_limit",
"fieldtype": "Int",
"label": "Payment Limit"
@@ -171,13 +174,17 @@
"fieldname": "maximum_invoice_amount",
"fieldtype": "Currency",
"label": "Maximum Invoice Amount"
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
"icon": "icon-resize-horizontal",
"issingle": 1,
"links": [],
"modified": "2021-08-30 13:05:51.977861",
"modified": "2021-10-04 20:27:11.114194",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",

View File

@@ -14,8 +14,8 @@
"section_break_6",
"allocated_amount",
"unreconciled_amount",
"amount",
"column_break_8",
"amount",
"is_advance",
"section_break_5",
"difference_amount",
@@ -127,12 +127,13 @@
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Row"
"label": "Reference Row",
"read_only": 1
}
],
"istable": 1,
"links": [],
"modified": "2021-09-20 17:23:09.455803",
"modified": "2021-10-06 11:48:59.616562",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Allocation",

View File

@@ -120,6 +120,7 @@
{
"fieldname": "payments",
"fieldtype": "Table",
"label": "Payment Methods",
"options": "POS Payment Method",
"reqd": 1
},
@@ -377,7 +378,7 @@
"link_fieldname": "pos_profile"
}
],
"modified": "2021-02-01 13:52:51.081311",
"modified": "2021-10-14 14:17:00.469298",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -149,16 +149,18 @@
"cb_17",
"hold_comment",
"more_info",
"status",
"inter_company_invoice_reference",
"represents_company",
"column_break_147",
"is_internal_supplier",
"accounting_details_section",
"credit_to",
"party_account_currency",
"is_opening",
"against_expense_account",
"column_break_63",
"unrealized_profit_loss_account",
"status",
"inter_company_invoice_reference",
"is_internal_supplier",
"represents_company",
"remarks",
"subscription_section",
"from_date",
@@ -1171,6 +1173,15 @@
"options": "fa fa-file-text",
"print_hide": 1
},
{
"default": "0",
"fetch_from": "supplier.is_internal_supplier",
"fieldname": "is_internal_supplier",
"fieldtype": "Check",
"ignore_user_permissions": 1,
"label": "Is Internal Supplier",
"read_only": 1
},
{
"fieldname": "credit_to",
"fieldtype": "Link",
@@ -1196,7 +1207,7 @@
"default": "No",
"fieldname": "is_opening",
"fieldtype": "Select",
"label": "Is Opening",
"label": "Is Opening Entry",
"oldfieldname": "is_opening",
"oldfieldtype": "Select",
"options": "No\nYes",
@@ -1298,15 +1309,6 @@
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"default": "0",
"fetch_from": "supplier.is_internal_supplier",
"fieldname": "is_internal_supplier",
"fieldtype": "Check",
"ignore_user_permissions": 1,
"label": "Is Internal Supplier",
"read_only": 1
},
{
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
@@ -1395,13 +1397,24 @@
"hidden": 1,
"label": "Ignore Default Payment Terms Template",
"read_only": 1
},
{
"collapsible": 1,
"fieldname": "accounting_details_section",
"fieldtype": "Section Break",
"label": "Accounting Details",
"print_hide": 1
},
{
"fieldname": "column_break_147",
"fieldtype": "Column Break"
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2021-09-28 13:10:28.351810",
"modified": "2021-10-12 20:55:16.145651",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -124,6 +124,13 @@
"total_advance",
"outstanding_amount",
"disable_rounded_total",
"column_break4",
"write_off_amount",
"base_write_off_amount",
"write_off_outstanding_amount_automatically",
"column_break_74",
"write_off_account",
"write_off_cost_center",
"advances_section",
"allocate_advances_automatically",
"get_advances",
@@ -144,13 +151,6 @@
"column_break_90",
"change_amount",
"account_for_change_amount",
"column_break4",
"write_off_amount",
"base_write_off_amount",
"write_off_outstanding_amount_automatically",
"column_break_74",
"write_off_account",
"write_off_cost_center",
"terms_section_break",
"tc_name",
"terms",
@@ -161,14 +161,14 @@
"column_break_84",
"language",
"more_information",
"status",
"inter_company_invoice_reference",
"is_internal_customer",
"represents_company",
"customer_group",
"campaign",
"is_discounted",
"col_break23",
"status",
"is_internal_customer",
"is_discounted",
"source",
"more_info",
"debit_to",
@@ -2031,7 +2031,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2021-10-02 03:36:10.251715",
"modified": "2021-10-11 20:19:38.667508",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -1284,12 +1284,20 @@ class SalesInvoice(SellingController):
serial_nos = item.serial_no or ""
si_serial_nos = set(get_serial_nos(serial_nos))
serial_no_diff = si_serial_nos - dn_serial_nos
if si_serial_nos - dn_serial_nos:
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note").format(item.idx))
if serial_no_diff:
dn_link = frappe.utils.get_link_to_form("Delivery Note", item.delivery_note)
serial_no_msg = ", ".join(frappe.bold(d) for d in serial_no_diff)
msg = _("Row #{0}: The following Serial Nos are not present in Delivery Note {1}:").format(
item.idx, dn_link)
msg += " " + serial_no_msg
frappe.throw(msg=msg, title=_("Serial Nos Mismatch"))
if item.serial_no and cint(item.qty) != len(si_serial_nos):
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
frappe.throw(_("Row #{0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
item.idx, item.qty, item.item_code, len(si_serial_nos)))
def update_project(self):

View File

@@ -1087,8 +1087,6 @@ class TestSalesInvoice(unittest.TestCase):
actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
frappe.db.commit()
self.assertEqual(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate
@@ -2357,6 +2355,18 @@ class TestSalesInvoice(unittest.TestCase):
si.reload()
self.assertEqual(si.status, "Paid")
def test_sales_invoice_submission_post_account_freezing_date(self):
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1))
si = create_sales_invoice(do_not_save=True)
si.posting_date = add_days(getdate(), 1)
si.save()
self.assertRaises(frappe.ValidationError, si.submit)
si.posting_date = getdate()
si.submit()
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None)
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'

View File

@@ -33,7 +33,7 @@ class Subscription(Document):
# update start just before the subscription doc is created
self.update_subscription_period(self.start_date)
def update_subscription_period(self, date=None):
def update_subscription_period(self, date=None, return_date=False):
"""
Subscription period is the period to be billed. This method updates the
beginning of the billing period and end of the billing period.
@@ -41,28 +41,41 @@ class Subscription(Document):
The beginning of the billing period is represented in the doctype as
`current_invoice_start` and the end of the billing period is represented
as `current_invoice_end`.
"""
self.set_current_invoice_start(date)
self.set_current_invoice_end()
def set_current_invoice_start(self, date=None):
If return_date is True, it wont update the start and end dates.
This is implemented to get the dates to check if is_current_invoice_generated
"""
This sets the date of the beginning of the current billing period.
_current_invoice_start = self.get_current_invoice_start(date)
_current_invoice_end = self.get_current_invoice_end(_current_invoice_start)
if return_date:
return _current_invoice_start, _current_invoice_end
self.current_invoice_start = _current_invoice_start
self.current_invoice_end = _current_invoice_end
def get_current_invoice_start(self, date=None):
"""
This returns the date of the beginning of the current billing period.
If the `date` parameter is not given , it will be automatically set as today's
date.
"""
if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date):
self.current_invoice_start = add_days(self.trial_period_end, 1)
elif self.trial_period_start and self.is_trialling():
self.current_invoice_start = self.trial_period_start
elif date:
self.current_invoice_start = date
else:
self.current_invoice_start = nowdate()
_current_invoice_start = None
def set_current_invoice_end(self):
if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date):
_current_invoice_start = add_days(self.trial_period_end, 1)
elif self.trial_period_start and self.is_trialling():
_current_invoice_start = self.trial_period_start
elif date:
_current_invoice_start = date
else:
_current_invoice_start = nowdate()
return _current_invoice_start
def get_current_invoice_end(self, date=None):
"""
This sets the date of the end of the current billing period.
This returns the date of the end of the current billing period.
If the subscription is in trial period, it will be set as the end of the
trial period.
@@ -71,44 +84,47 @@ class Subscription(Document):
current billing period where `x` is the billing interval from the
`Subscription Plan` in the `Subscription`.
"""
if self.is_trialling() and getdate(self.current_invoice_start) < getdate(self.trial_period_end):
self.current_invoice_end = self.trial_period_end
_current_invoice_end = None
if self.is_trialling() and getdate(date) < getdate(self.trial_period_end):
_current_invoice_end = self.trial_period_end
else:
billing_cycle_info = self.get_billing_cycle_data()
if billing_cycle_info:
if self.is_new_subscription() and getdate(self.start_date) < getdate(self.current_invoice_start):
self.current_invoice_end = add_to_date(self.start_date, **billing_cycle_info)
if self.is_new_subscription() and getdate(self.start_date) < getdate(date):
_current_invoice_end = add_to_date(self.start_date, **billing_cycle_info)
# For cases where trial period is for an entire billing interval
if getdate(self.current_invoice_end) < getdate(self.current_invoice_start):
self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info)
if getdate(self.current_invoice_end) < getdate(date):
_current_invoice_end = add_to_date(date, **billing_cycle_info)
else:
self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info)
_current_invoice_end = add_to_date(date, **billing_cycle_info)
else:
self.current_invoice_end = get_last_day(self.current_invoice_start)
_current_invoice_end = get_last_day(date)
if self.follow_calendar_months:
billing_info = self.get_billing_cycle_and_interval()
billing_interval_count = billing_info[0]['billing_interval_count']
calendar_months = get_calendar_months(billing_interval_count)
calendar_month = 0
current_invoice_end_month = getdate(self.current_invoice_end).month
current_invoice_end_year = getdate(self.current_invoice_end).year
current_invoice_end_month = getdate(_current_invoice_end).month
current_invoice_end_year = getdate(_current_invoice_end).year
for month in calendar_months:
if month <= current_invoice_end_month:
calendar_month = month
if cint(calendar_month - billing_interval_count) <= 0 and \
getdate(self.current_invoice_start).month != 1:
getdate(date).month != 1:
calendar_month = 12
current_invoice_end_year -= 1
self.current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' \
+ cstr(calendar_month) + '-01')
_current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' + cstr(calendar_month) + '-01')
if self.end_date and getdate(self.current_invoice_end) > getdate(self.end_date):
self.current_invoice_end = self.end_date
if self.end_date and getdate(_current_invoice_end) > getdate(self.end_date):
_current_invoice_end = self.end_date
return _current_invoice_end
@staticmethod
def validate_plans_billing_cycle(billing_cycle_data):
@@ -488,8 +504,9 @@ class Subscription(Document):
def is_current_invoice_generated(self):
invoice = self.get_current_invoice()
_current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
if invoice and getdate(self.current_invoice_start) <= getdate(invoice.posting_date) <= getdate(self.current_invoice_end):
if invoice and getdate(_current_start_date) <= getdate(invoice.posting_date) <= getdate(_current_end_date):
return True
return False
@@ -542,15 +559,15 @@ class Subscription(Document):
else:
self.set_status_grace_period()
if getdate() > getdate(self.current_invoice_end):
self.update_subscription_period(add_days(self.current_invoice_end, 1))
# Generate invoices periodically even if current invoice are unpaid
if self.generate_new_invoices_past_due_date and not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice()
or self.is_prepaid_to_invoice()):
prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
self.generate_invoice(prorate)
if getdate() > getdate(self.current_invoice_end):
self.update_subscription_period(add_days(self.current_invoice_end, 1))
@staticmethod
def is_paid(invoice):
"""

View File

@@ -18,6 +18,7 @@ from frappe.utils.data import (
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
test_dependencies = ("UOM", "Item Group", "Item")
def create_plan():
if not frappe.db.exists('Subscription Plan', '_Test Plan Name'):
@@ -68,7 +69,6 @@ def create_plan():
supplier.insert()
class TestSubscription(unittest.TestCase):
def setUp(self):
create_plan()

View File

@@ -203,6 +203,9 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
# then chargeable value is "prev invoices + advances" value which cross the threshold
tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers)
if cint(tax_details.round_off_tax_amount):
tax_amount = round(tax_amount)
return tax_amount, tax_deducted
def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'):
@@ -322,9 +325,6 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
else:
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
if cint(tax_details.round_off_tax_amount):
tds_amount = round(tds_amount)
return tds_amount
def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):

View File

@@ -293,7 +293,7 @@ def check_freezing_date(posting_date, adv_adj=False):
if acc_frozen_upto:
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
if getdate(posting_date) <= getdate(acc_frozen_upto) \
and not frozen_accounts_modifier in frappe.get_roles() or frappe.session.user == 'Administrator':
and (frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == 'Administrator'):
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
def set_as_cancel(voucher_type, voucher_no):

View File

@@ -103,8 +103,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
column.is_tree = true;
}
value = default_formatter(value, row, column, data);
if (data && data.account && column.apply_currency_formatter) {
data.currency = erpnext.get_currency(column.company_name);
}
value = default_formatter(value, row, column, data);
if (!data.parent_account) {
value = $(`<span>${value}</span>`);

View File

@@ -3,12 +3,14 @@
from __future__ import unicode_literals
from collections import defaultdict
import frappe
from frappe import _
from frappe.utils import cint, flt, getdate
import erpnext
from erpnext.accounts.report.balance_sheet.balance_sheet import (
check_opening_balance,
get_chart_data,
get_provisional_profit_loss,
)
@@ -31,7 +33,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (
get_report_summary as get_pl_summary,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency
from erpnext.accounts.report.utils import convert, convert_to_presentation_currency
def execute(filters=None):
@@ -42,7 +44,7 @@ def execute(filters=None):
fiscal_year = get_fiscal_year_data(filters.get('from_fiscal_year'), filters.get('to_fiscal_year'))
companies_column, companies = get_companies(filters)
columns = get_columns(companies_column)
columns = get_columns(companies_column, filters)
if filters.get('report') == "Balance Sheet":
data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters)
@@ -73,21 +75,24 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
companies, filters.get('company'), company_currency, True)
message, opening_balance = check_opening_balance(asset, liability, equity)
message, opening_balance = prepare_companywise_opening_balance(asset, liability, equity, companies)
if opening_balance and round(opening_balance,2) !=0:
unclosed ={
if opening_balance:
unclosed = {
"account_name": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
"account": "'" + _("Unclosed Fiscal Years Profit / Loss (Credit)") + "'",
"warn_if_negative": True,
"currency": company_currency
}
for company in companies:
unclosed[company] = opening_balance
if provisional_profit_loss:
provisional_profit_loss[company] = provisional_profit_loss[company] - opening_balance
unclosed["total"]=opening_balance
for company in companies:
unclosed[company] = opening_balance.get(company)
if provisional_profit_loss and provisional_profit_loss.get(company):
provisional_profit_loss[company] = (
flt(provisional_profit_loss[company]) - flt(opening_balance.get(company))
)
unclosed["total"] = opening_balance.get(company)
data.append(unclosed)
if provisional_profit_loss:
@@ -102,6 +107,37 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
return data, message, chart, report_summary
def prepare_companywise_opening_balance(asset_data, liability_data, equity_data, companies):
opening_balance = {}
for company in companies:
opening_value = 0
# opening_value = Aseet - liability - equity
for data in [asset_data, liability_data, equity_data]:
account_name = get_root_account_name(data[0].root_type, company)
opening_value += get_opening_balance(account_name, data, company)
opening_balance[company] = opening_value
if opening_balance:
return _("Previous Financial Year is not closed"), opening_balance
return '', {}
def get_opening_balance(account_name, data, company):
for row in data:
if row.get('account_name') == account_name:
return row.get('company_wise_opening_bal', {}).get(company, 0.0)
def get_root_account_name(root_type, company):
return frappe.get_all(
'Account',
fields=['account_name'],
filters = {'root_type': root_type, 'is_group': 1,
'company': company, 'parent_account': ('is', 'not set')},
as_list=1
)[0][0]
def get_profit_loss_data(fiscal_year, companies, columns, filters):
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
company_currency = get_company_currency(filters)
@@ -193,30 +229,37 @@ def get_account_type_based_data(account_type, companies, fiscal_year, filters):
data["total"] = total
return data
def get_columns(companies):
columns = [{
"fieldname": "account",
"label": _("Account"),
"fieldtype": "Link",
"options": "Account",
"width": 300
}]
columns.append({
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Link",
"options": "Currency",
"hidden": 1
})
def get_columns(companies, filters):
columns = [
{
"fieldname": "account",
"label": _("Account"),
"fieldtype": "Link",
"options": "Account",
"width": 300
}, {
"fieldname": "currency",
"label": _("Currency"),
"fieldtype": "Link",
"options": "Currency",
"hidden": 1
}
]
for company in companies:
apply_currency_formatter = 1 if not filters.presentation_currency else 0
currency = filters.presentation_currency
if not currency:
currency = erpnext.get_company_currency(company)
columns.append({
"fieldname": company,
"label": company,
"label": f'{company} ({currency})',
"fieldtype": "Currency",
"options": "currency",
"width": 150
"width": 150,
"apply_currency_formatter": apply_currency_formatter,
"company_name": company
})
return columns
@@ -236,6 +279,8 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
end_date = filters.period_end_date
filters.end_date = end_date
gl_entries_by_account = {}
for root in frappe.db.sql("""select lft, rgt from tabAccount
where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
@@ -244,9 +289,10 @@ def get_data(companies, root_type, balance_must_be, fiscal_year, filters=None, i
end_date, root.lft, root.rgt, filters,
gl_entries_by_account, accounts_by_name, accounts, ignore_closing_entries=False)
calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters)
calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year)
accumulate_values_into_parents(accounts, accounts_by_name, companies)
out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency)
out = prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters)
if out:
add_total_row(out, root_type, balance_must_be, companies, company_currency)
@@ -257,7 +303,10 @@ def get_company_currency(filters=None):
return (filters.get('presentation_currency')
or frappe.get_cached_value('Company', filters.company, "default_currency"))
def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_date, filters):
def calculate_values(accounts_by_name, gl_entries_by_account, companies, filters, fiscal_year):
start_date = (fiscal_year.year_start_date
if filters.filter_based_on == 'Fiscal Year' else filters.period_start_date)
for entries in gl_entries_by_account.values():
for entry in entries:
if entry.account_number:
@@ -266,15 +315,32 @@ def calculate_values(accounts_by_name, gl_entries_by_account, companies, start_d
account_name = entry.account_name
d = accounts_by_name.get(account_name)
if d:
debit, credit = 0, 0
for company in companies:
# check if posting date is within the period
if (entry.company == company or (filters.get('accumulated_in_group_company'))
and entry.company in companies.get(company)):
d[company] = d.get(company, 0.0) + flt(entry.debit) - flt(entry.credit)
parent_company_currency = erpnext.get_company_currency(d.company)
child_company_currency = erpnext.get_company_currency(entry.company)
debit, credit = flt(entry.debit), flt(entry.credit)
if (not filters.get('presentation_currency')
and entry.company != company
and parent_company_currency != child_company_currency
and filters.get('accumulated_in_group_company')):
debit = convert(debit, parent_company_currency, child_company_currency, filters.end_date)
credit = convert(credit, parent_company_currency, child_company_currency, filters.end_date)
d[company] = d.get(company, 0.0) + flt(debit) - flt(credit)
if entry.posting_date < getdate(start_date):
d['company_wise_opening_bal'][company] += (flt(debit) - flt(credit))
if entry.posting_date < getdate(start_date):
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(debit) - flt(credit)
def accumulate_values_into_parents(accounts, accounts_by_name, companies):
"""accumulate children's values in parent accounts"""
@@ -282,17 +348,18 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies):
if d.parent_account:
account = d.parent_account_name
if not accounts_by_name.get(account):
continue
# if not accounts_by_name.get(account):
# continue
for company in companies:
accounts_by_name[account][company] = \
accounts_by_name[account].get(company, 0.0) + d.get(company, 0.0)
accounts_by_name[account]['company_wise_opening_bal'][company] += d.get('company_wise_opening_bal', {}).get(company, 0.0)
accounts_by_name[account]["opening_balance"] = \
accounts_by_name[account].get("opening_balance", 0.0) + d.get("opening_balance", 0.0)
def get_account_heads(root_type, companies, filters):
accounts = get_accounts(root_type, filters)
@@ -353,7 +420,7 @@ def get_accounts(root_type, filters):
`tabAccount` where company = %s and root_type = %s
""" , (filters.get('company'), root_type), as_dict=1)
def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency):
def prepare_data(accounts, start_date, end_date, balance_must_be, companies, company_currency, filters):
data = []
for d in accounts:
@@ -367,10 +434,13 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
"parent_account": _(d.parent_account),
"indent": flt(d.indent),
"year_start_date": start_date,
"root_type": d.root_type,
"year_end_date": end_date,
"currency": company_currency,
"currency": filters.presentation_currency,
"company_wise_opening_bal": d.company_wise_opening_bal,
"opening_balance": d.get("opening_balance", 0.0) * (1 if balance_must_be == "Debit" else -1)
})
for company in companies:
if d.get(company) and balance_must_be == "Credit":
# change sign based on Debit or Credit, since calculation is done using (debit - credit)
@@ -385,6 +455,7 @@ def prepare_data(accounts, start_date, end_date, balance_must_be, companies, com
row["has_value"] = has_value
row["total"] = total
data.append(row)
return data
@@ -447,6 +518,7 @@ def get_account_details(account):
'is_group', 'account_name', 'account_number', 'parent_account', 'lft', 'rgt'], as_dict=1)
def validate_entries(key, entry, accounts_by_name, accounts):
# If an account present in the child company and not in the parent company
if key not in accounts_by_name:
args = get_account_details(entry.account)
@@ -456,12 +528,23 @@ def validate_entries(key, entry, accounts_by_name, accounts):
args.update({
'lft': parent_args.lft + 1,
'rgt': parent_args.rgt - 1,
'indent': 3,
'root_type': parent_args.root_type,
'report_type': parent_args.report_type
'report_type': parent_args.report_type,
'parent_account_name': parent_args.account_name,
'company_wise_opening_bal': defaultdict(float)
})
accounts_by_name.setdefault(key, args)
accounts.append(args)
idx = len(accounts)
# To identify parent account index
for index, row in enumerate(accounts):
if row.parent_account_name == args.parent_account_name:
idx = index
break
accounts.insert(idx+1, args)
def get_additional_conditions(from_date, ignore_closing_entries, filters):
additional_conditions = []
@@ -491,7 +574,6 @@ def add_total_row(out, root_type, balance_must_be, companies, company_currency):
for company in companies:
total_row.setdefault(company, 0.0)
total_row[company] += row.get(company, 0.0)
row[company] = 0.0
total_row.setdefault("total", 0.0)
total_row["total"] += flt(row["total"])
@@ -511,6 +593,7 @@ def filter_accounts(accounts, depth=10):
account_name = d.account_number + ' - ' + d.account_name
else:
account_name = d.account_name
d['company_wise_opening_bal'] = defaultdict(float)
accounts_by_name[account_name] = d
parent_children_map.setdefault(d.parent_account or None, []).append(d)

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Profit and Loss",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Accounts\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Profit and Loss\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chart of Accounts\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Invoice\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Invoice\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Journal Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Payment Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Accounts Receivable\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"General Ledger\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Trial Balance\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounting Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"General Ledger\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounts Receivable\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Accounts Payable\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Financial Statements\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Multi Currency\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Bank Statement\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Subscription Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Goods and Services Tax (GST India)\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Share Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Cost Center and Budgeting\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Opening and Closing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Taxes\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Profitability\", \"col\": 4}}]",
"creation": "2020-03-02 15:41:59.515192",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "accounting",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Accounting",
"links": [
{
@@ -533,6 +526,17 @@
"only_for": "United Arab Emirates",
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "KSA VAT Report",
"link_to": "KSA VAT",
"link_type": "Report",
"onboard": 0,
"only_for": "Saudi Arabia",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -1153,6 +1157,16 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "KSA VAT Setting",
"link_to": "KSA VAT Setting",
"link_type": "DocType",
"onboard": 0,
"only_for": "Saudi Arabia",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -1206,15 +1220,12 @@
"type": "Link"
}
],
"modified": "2021-08-27 12:15:52.872470",
"modified": "2021-08-27 12:15:52.872471",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",
"onboarding": "Accounts",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Crops & Lands\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Analytics\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Diseases & Fertilizers\", \"col\": 4}}]",
"creation": "2020-03-02 17:23:34.339274",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "agriculture",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Agriculture",
"links": [
{
@@ -163,15 +156,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:54.595197",
"modified": "2021-08-05 12:15:54.595198",
"modified_by": "Administrator",
"module": "Agriculture",
"name": "Agriculture",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "Agriculture",
"roles": [],

View File

@@ -194,7 +194,7 @@ class Asset(AccountsController):
start = self.clear_depreciation_schedule()
# value_after_depreciation - current Asset value
if d.value_after_depreciation:
if self.docstatus == 1 and d.value_after_depreciation:
value_after_depreciation = (flt(d.value_after_depreciation) -
flt(self.opening_accumulated_depreciation))
else:

View File

@@ -682,6 +682,27 @@ class TestAsset(unittest.TestCase):
# reset indian company
frappe.flags.company = company_flag
def test_expected_value_change(self):
"""
tests if changing `expected_value_after_useful_life`
affects `value_after_depreciation`
"""
asset = create_asset(calculate_depreciation=1)
asset.opening_accumulated_depreciation = 2000
asset.number_of_depreciations_booked = 1
asset.finance_books[0].expected_value_after_useful_life = 100
asset.save()
asset.reload()
self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
# changing expected_value_after_useful_life shouldn't affect value_after_depreciation
asset.finance_books[0].expected_value_after_useful_life = 200
asset.save()
asset.reload()
self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0)
def create_asset_data():
if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category()

View File

@@ -22,7 +22,7 @@ class TestAssetRepair(unittest.TestCase):
frappe.db.sql("delete from `tabTax Rule`")
def test_update_status(self):
asset = create_asset()
asset = create_asset(submit=1)
initial_status = asset.status
asset_repair = create_asset_repair(asset = asset)
@@ -76,7 +76,7 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(stock_entry.items[0].qty, asset_repair.stock_items[0].consumed_quantity)
def test_increase_in_asset_value_due_to_stock_consumption(self):
asset = create_asset(calculate_depreciation = 1)
asset = create_asset(calculate_depreciation = 1, submit=1)
initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, stock_consumption = 1, submit = 1)
asset.reload()
@@ -85,7 +85,7 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(asset_repair.stock_items[0].total_value, increase_in_asset_value)
def test_increase_in_asset_value_due_to_repair_cost_capitalisation(self):
asset = create_asset(calculate_depreciation = 1)
asset = create_asset(calculate_depreciation = 1, submit=1)
initial_asset_value = get_asset_value(asset)
asset_repair = create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset.reload()
@@ -103,7 +103,7 @@ class TestAssetRepair(unittest.TestCase):
self.assertEqual(asset_repair.name, gl_entry.voucher_no)
def test_increase_in_asset_life(self):
asset = create_asset(calculate_depreciation = 1)
asset = create_asset(calculate_depreciation = 1, submit=1)
initial_num_of_depreciations = num_of_depreciations(asset)
create_asset_repair(asset= asset, capitalize_repair_cost = 1, submit = 1)
asset.reload()
@@ -126,7 +126,7 @@ def create_asset_repair(**args):
if args.asset:
asset = args.asset
else:
asset = create_asset(is_existing_asset = 1)
asset = create_asset(is_existing_asset = 1, submit=1)
asset_repair = frappe.new_doc("Asset Repair")
asset_repair.update({
"asset": asset.name,

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Asset Value Analytics",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Assets\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Asset Value Analytics\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Asset\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Asset Category\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Fixed Asset Register\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assets\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Maintenance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
"creation": "2020-03-02 15:43:27.634865",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "assets",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Assets",
"links": [
{
@@ -179,15 +172,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:54.839452",
"modified": "2021-08-05 12:15:54.839453",
"modified_by": "Administrator",
"module": "Assets",
"name": "Assets",
"onboarding": "Assets",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -11,7 +11,7 @@ frappe.tour['Buying Settings'] = [
{
fieldname: "supp_master_name",
title: "Supplier Naming By",
description: __("By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a ") + "<a href='https://docs.erpnext.com/docs/user/manual/en/setting-up/settings/naming-series' target='_blank'>Naming Series</a>" + __(" choose the 'Naming Series' option."),
description: __("By default, the Supplier Name is set as per the Supplier Name entered. If you want Suppliers to be named by a <a href='https://docs.erpnext.com/docs/user/manual/en/setting-up/settings/naming-series' target='_blank'>Naming Series</a> choose the 'Naming Series' option."),
},
{
fieldname: "buying_price_list",

View File

@@ -0,0 +1,77 @@
{
"creation": "2021-07-28 11:51:42.319984",
"docstatus": 0,
"doctype": "Form Tour",
"idx": 0,
"is_standard": 1,
"modified": "2021-10-05 13:06:56.414584",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
"owner": "Administrator",
"reference_doctype": "Buying Settings",
"save_on_complete": 0,
"steps": [
{
"description": "When a Supplier is saved, system generates a unique identity or name for that Supplier which can be used to refer the Supplier in various Buying transactions.",
"field": "",
"fieldname": "supp_master_name",
"fieldtype": "Select",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Supplier Naming By",
"parent_field": "",
"position": "Bottom",
"title": "Supplier Naming By"
},
{
"description": "Configure what should be the default value of Supplier Group when creating a new Supplier.",
"field": "",
"fieldname": "supplier_group",
"fieldtype": "Link",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Default Supplier Group",
"parent_field": "",
"position": "Right",
"title": "Default Supplier Group"
},
{
"description": "Item prices will be fetched from this Price List.",
"field": "",
"fieldname": "buying_price_list",
"fieldtype": "Link",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Default Buying Price List",
"parent_field": "",
"position": "Bottom",
"title": "Default Buying Price List"
},
{
"description": "If this option is configured \"Yes\", ERPNext will prevent you from creating a Purchase Invoice or a Purchase Receipt directly without creating a Purchase Order first.",
"field": "",
"fieldname": "po_required",
"fieldtype": "Select",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Is Purchase Order Required for Purchase Invoice & Receipt Creation?",
"parent_field": "",
"position": "Bottom",
"title": "Purchase Order Required"
},
{
"description": "If this option is configured \"Yes\", ERPNext will prevent you from creating a Purchase Invoice without creating a Purchase Receipt first.",
"field": "",
"fieldname": "pr_required",
"fieldtype": "Select",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Is Purchase Receipt Required for Purchase Invoice Creation?",
"parent_field": "",
"position": "Bottom",
"title": "Purchase Receipt Required"
}
],
"title": "Buying Settings"
}

View File

@@ -0,0 +1,82 @@
{
"creation": "2021-07-29 14:11:58.271113",
"docstatus": 0,
"doctype": "Form Tour",
"idx": 0,
"is_standard": 1,
"modified": "2021-10-05 13:11:31.436135",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
"owner": "Administrator",
"reference_doctype": "Purchase Order",
"save_on_complete": 1,
"steps": [
{
"description": "Select a Supplier",
"field": "",
"fieldname": "supplier",
"fieldtype": "Link",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Supplier",
"parent_field": "",
"position": "Right",
"title": "Supplier"
},
{
"description": "Set the \"Required By\" date for the materials. This sets the \"Required By\" date for all the items.",
"field": "",
"fieldname": "schedule_date",
"fieldtype": "Date",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Required By",
"parent_field": "",
"position": "Left",
"title": "Required By"
},
{
"description": "Items to be purchased can be added here.",
"field": "",
"fieldname": "items",
"fieldtype": "Table",
"has_next_condition": 0,
"is_table_field": 0,
"label": "Items",
"parent_field": "",
"position": "Bottom",
"title": "Items Table"
},
{
"child_doctype": "Purchase Order Item",
"description": "Enter the Item Code.",
"field": "",
"fieldname": "item_code",
"fieldtype": "Link",
"has_next_condition": 1,
"is_table_field": 1,
"label": "Item Code",
"next_step_condition": "eval: doc.item_code",
"parent_field": "",
"parent_fieldname": "items",
"position": "Right",
"title": "Item Code"
},
{
"child_doctype": "Purchase Order Item",
"description": "Enter the required quantity for the material.",
"field": "",
"fieldname": "qty",
"fieldtype": "Float",
"has_next_condition": 0,
"is_table_field": 1,
"label": "Quantity",
"parent_field": "",
"parent_fieldname": "items",
"position": "Bottom",
"title": "Quantity"
}
],
"title": "Purchase Order"
}

View File

@@ -19,7 +19,7 @@
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/buying",
"idx": 0,
"is_complete": 0,
"modified": "2020-07-08 14:05:28.273641",
"modified": "2021-08-24 18:13:42.463776",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying",
@@ -28,23 +28,11 @@
{
"step": "Introduction to Buying"
},
{
"step": "Create a Supplier"
},
{
"step": "Setup your Warehouse"
},
{
"step": "Create a Product"
},
{
"step": "Create a Material Request"
},
{
"step": "Create your first Purchase Order"
},
{
"step": "Buying Settings"
}
],
"subtitle": "Products, Purchases, Analysis, and more.",

View File

@@ -1,19 +1,21 @@
{
"action": "Create Entry",
"action": "Show Form Tour",
"action_label": "Let\u2019s create your first Material Request",
"creation": "2020-05-15 14:39:09.818764",
"description": "# Track Material Request\n\n\nAlso known as Purchase Request or an Indent, is a document identifying a requirement of a set of items (products or services) for various purposes like procurement, transfer, issue, or manufacturing. Once the Material Request is validated, a purchase manager can take the next actions for purchasing items like requesting RFQ from a supplier or directly placing an order with an identified Supplier.\n\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-15 14:39:09.818764",
"modified": "2021-08-24 18:08:08.347501",
"modified_by": "Administrator",
"name": "Create a Material Request",
"owner": "Administrator",
"reference_document": "Material Request",
"show_form_tour": 1,
"show_full_form": 1,
"title": "Create a Material Request",
"title": "Track Material Request",
"validate_action": 1
}

View File

@@ -1,19 +1,21 @@
{
"action": "Create Entry",
"action": "Show Form Tour",
"action_label": "Let\u2019s create your first Purchase Order",
"creation": "2020-05-12 18:17:49.976035",
"description": "# Create first Purchase Order\n\nPurchase Order is at the heart of your buying transactions. In ERPNext, Purchase Order can can be created against a Purchase Material Request (indent) and Supplier Quotation as well. Purchase Orders is also linked to Purchase Receipt and Purchase Invoices, allowing you to keep a birds-eye view on your purchase deals.\n\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-05-12 18:31:56.856112",
"modified": "2021-08-24 18:08:08.936484",
"modified_by": "Administrator",
"name": "Create your first Purchase Order",
"owner": "Administrator",
"reference_document": "Purchase Order",
"show_form_tour": 0,
"show_full_form": 0,
"title": "Create your first Purchase Order",
"title": "Create first Purchase Order",
"validate_action": 1
}

View File

@@ -1,19 +1,22 @@
{
"action": "Watch Video",
"action": "Show Form Tour",
"action_label": "Let\u2019s walk-through few Buying Settings",
"creation": "2020-05-06 15:37:09.477765",
"description": "# Buying Settings\n\n\nBuying module\u2019s features are highly configurable as per your business needs. Buying Settings is the place where you can set your preferences for:\n\n- Supplier naming and default values\n- Billing and shipping preference in buying transactions\n\n\n",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_single": 1,
"is_skipped": 0,
"modified": "2020-05-12 18:25:08.509900",
"modified": "2021-08-24 18:08:08.345735",
"modified_by": "Administrator",
"name": "Introduction to Buying",
"owner": "Administrator",
"show_full_form": 0,
"title": "Introduction to Buying",
"reference_document": "Buying Settings",
"show_form_tour": 1,
"show_full_form": 1,
"title": "Buying Settings",
"validate_action": 1,
"video_url": "https://youtu.be/efFajTTQBa8"
}

View File

@@ -45,7 +45,6 @@ class TestProcurementTracker(unittest.TestCase):
pr = make_purchase_receipt(po.name)
pr.get("items")[0].cost_center = "Main - _TPC"
pr.submit()
frappe.db.commit()
date_obj = datetime.date(datetime.now())
po.load_from_db()

View File

@@ -1,27 +1,18 @@
{
"cards_label": "",
"category": "",
"charts": [
{
"chart_name": "Purchase Order Trends",
"label": "Purchase Order Trends"
}
],
"charts_label": "",
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Buying\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Purchase Order Trends\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Material Request\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Purchase Order Analysis\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Buying\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Items & Pricing\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Supplier\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Supplier Scorecard\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Regional\", \"col\": 4}}]",
"creation": "2020-01-28 11:50:26.195467",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "buying",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Buying",
"links": [
{
@@ -518,15 +509,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:56.218427",
"modified": "2021-08-05 12:15:56.218428",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying",
"onboarding": "Buying",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],
@@ -572,6 +560,5 @@
"type": "Dashboard"
}
],
"shortcuts_label": "",
"title": "Buying"
}

View File

@@ -79,8 +79,15 @@ class StockController(AccountsController):
def clean_serial_nos(self):
for row in self.get("items"):
if hasattr(row, "serial_no") and row.serial_no:
# replace commas by linefeed and remove all spaces in string
row.serial_no = row.serial_no.replace(",", "\n").replace(" ", "")
# replace commas by linefeed
row.serial_no = row.serial_no.replace(",", "\n")
# strip preceeding and succeeding spaces for each SN
# (SN could have valid spaces in between e.g. SN - 123 - 2021)
serial_no_list = row.serial_no.split("\n")
serial_no_list = [sn.strip() for sn in serial_no_list]
row.serial_no = "\n".join(serial_no_list)
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
default_cost_center=None):
@@ -591,7 +598,7 @@ def future_sle_exists(args, sl_entries=None):
data = frappe.db.sql("""
select item_code, warehouse, count(name) as total_row
from `tabStock Ledger Entry`
from `tabStock Ledger Entry` force index (item_warehouse)
where
({})
and timestamp(posting_date, posting_time)

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Territory Wise Sales"
@@ -7,18 +6,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"CRM\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": null, \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Lead\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Opportunity\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Customer\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Sales Analytics\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Sales Pipeline\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Maintenance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Campaign\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]",
"creation": "2020-01-23 14:48:30.183272",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "crm",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "CRM",
"links": [
{
@@ -421,15 +414,12 @@
"type": "Link"
}
],
"modified": "2021-08-19 19:08:08.728876",
"modified": "2021-08-20 12:15:56.913092",
"modified_by": "Administrator",
"module": "CRM",
"name": "CRM",
"onboarding": "CRM",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Program Enrollments",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Education\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Program Enrollments\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Instructor\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Program\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Course\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Fees\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student Monthly Attendance Sheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Course Scheduling Tool\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Student Attendance Tool\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Student and Instructor\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Content Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Admission\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Fees\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Schedule\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"LMS Activity\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assessment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Assessment Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]",
"creation": "2020-03-02 17:22:57.066401",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "education",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Education",
"links": [
{
@@ -699,15 +692,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:57.929275",
"modified": "2021-08-05 12:15:57.929276",
"modified_by": "Administrator",
"module": "Education",
"name": "Education",
"onboarding": "Education",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "Education",
"roles": [],

View File

@@ -0,0 +1,51 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2021-09-11 05:09:53.773838",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"region",
"region_code",
"country",
"country_code"
],
"fields": [
{
"fieldname": "region",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Region"
},
{
"fieldname": "region_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Region Code"
},
{
"fieldname": "country",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Country"
},
{
"fieldname": "country_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Country Code"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-09-14 05:33:06.444710",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "TaxJar Nexus",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class TaxJarNexus(Document):
pass

View File

@@ -5,5 +5,16 @@ frappe.ui.form.on('TaxJar Settings', {
is_sandbox: (frm) => {
frm.toggle_reqd("api_key", !frm.doc.is_sandbox);
frm.toggle_reqd("sandbox_api_key", frm.doc.is_sandbox);
}
},
refresh: (frm) => {
frm.add_custom_button(__('Update Nexus List'), function() {
frm.call({
doc: frm.doc,
method: 'update_nexus_list'
});
});
},
});

View File

@@ -6,8 +6,8 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"is_sandbox",
"taxjar_calculate_tax",
"is_sandbox",
"taxjar_create_transactions",
"credentials",
"api_key",
@@ -16,7 +16,10 @@
"configuration",
"tax_account_head",
"configuration_cb",
"shipping_account_head"
"shipping_account_head",
"section_break_12",
"nexus_address",
"nexus"
],
"fields": [
{
@@ -54,6 +57,7 @@
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "is_sandbox",
"fieldtype": "Check",
"label": "Sandbox Mode"
@@ -69,6 +73,7 @@
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "taxjar_create_transactions",
"fieldtype": "Check",
"label": "Create TaxJar Transaction"
@@ -82,11 +87,28 @@
{
"fieldname": "cb_keys",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_12",
"fieldtype": "Section Break",
"label": "Nexus List"
},
{
"fieldname": "nexus_address",
"fieldtype": "HTML",
"label": "Nexus Address"
},
{
"fieldname": "nexus",
"fieldtype": "Table",
"label": "Nexus",
"options": "TaxJar Nexus",
"read_only": 1
}
],
"issingle": 1,
"links": [],
"modified": "2020-04-30 04:38:03.311089",
"modified": "2021-10-06 10:59:13.475442",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "TaxJar Settings",

View File

@@ -4,9 +4,98 @@
from __future__ import unicode_literals
# import frappe
import json
import os
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.model.document import Document
from frappe.permissions import add_permission, update_permission_property
from erpnext.erpnext_integrations.taxjar_integration import get_client
class TaxJarSettings(Document):
pass
def on_update(self):
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox")
fields_already_exist = frappe.db.exists('Custom Field', {'dt': ('in', ['Item','Sales Invoice Item']), 'fieldname':'product_tax_category'})
fields_hidden = frappe.get_value('Custom Field', {'dt': ('in', ['Sales Invoice Item'])}, 'hidden')
if (TAXJAR_CREATE_TRANSACTIONS or TAXJAR_CALCULATE_TAX or TAXJAR_SANDBOX_MODE):
if not fields_already_exist:
add_product_tax_categories()
make_custom_fields()
add_permissions()
frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=False)
elif fields_already_exist and fields_hidden:
toggle_tax_category_fields(hidden='0')
elif fields_already_exist:
toggle_tax_category_fields(hidden='1')
def validate(self):
self.calculate_taxes_validation_for_create_transactions()
@frappe.whitelist()
def update_nexus_list(self):
client = get_client()
nexus = client.nexus_regions()
new_nexus_list = [frappe._dict(address) for address in nexus]
self.set('nexus', [])
self.set('nexus', new_nexus_list)
self.save()
def calculate_taxes_validation_for_create_transactions(self):
if not self.taxjar_calculate_tax and (self.taxjar_create_transactions or self.is_sandbox):
frappe.throw(frappe._('Before enabling <b>Create Transaction</b> or <b>Sandbox Mode</b>, you need to check the <b>Enable Tax Calculation</b> box'))
def toggle_tax_category_fields(hidden):
frappe.set_value('Custom Field', {'dt':'Sales Invoice Item', 'fieldname':'product_tax_category'}, 'hidden', hidden)
frappe.set_value('Custom Field', {'dt':'Item', 'fieldname':'product_tax_category'}, 'hidden', hidden)
def add_product_tax_categories():
with open(os.path.join(os.path.dirname(__file__), 'product_tax_category_data.json'), 'r') as f:
tax_categories = json.loads(f.read())
create_tax_categories(tax_categories['categories'])
def create_tax_categories(data):
for d in data:
if not frappe.db.exists('Product Tax Category',{'product_tax_code':d.get('product_tax_code')}):
tax_category = frappe.new_doc('Product Tax Category')
tax_category.description = d.get("description")
tax_category.product_tax_code = d.get("product_tax_code")
tax_category.category_name = d.get("name")
tax_category.db_insert()
def make_custom_fields(update=True):
custom_fields = {
'Sales Invoice Item': [
dict(fieldname='product_tax_category', fieldtype='Link', insert_after='description', options='Product Tax Category',
label='Product Tax Category', fetch_from='item_code.product_tax_category'),
dict(fieldname='tax_collectable', fieldtype='Currency', insert_after='net_amount',
label='Tax Collectable', read_only=1),
dict(fieldname='taxable_amount', fieldtype='Currency', insert_after='tax_collectable',
label='Taxable Amount', read_only=1)
],
'Item': [
dict(fieldname='product_tax_category', fieldtype='Link', insert_after='item_group', options='Product Tax Category',
label='Product Tax Category')
]
}
create_custom_fields(custom_fields, update=update)
def add_permissions():
doctype = "Product Tax Category"
for role in ('Accounts Manager', 'Accounts User', 'System Manager','Item Manager', 'Stock Manager'):
add_permission(doctype, role, 0)
update_permission_property(doctype, role, 0, 'write', 1)
update_permission_property(doctype, role, 0, 'create', 1)

View File

@@ -4,7 +4,7 @@ import frappe
import taxjar
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
from frappe.utils import cint
from frappe.utils import cint, flt
from erpnext import get_default_company
@@ -103,7 +103,7 @@ def get_tax_data(doc):
shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD])
line_items = [get_line_item_dict(item) for item in doc.items]
line_items = [get_line_item_dict(item, doc.docstatus) for item in doc.items]
if from_shipping_state not in SUPPORTED_STATE_CODES:
from_shipping_state = get_state_code(from_address, 'Company')
@@ -139,14 +139,21 @@ def get_state_code(address, location):
return state_code
def get_line_item_dict(item):
return dict(
def get_line_item_dict(item, docstatus):
tax_dict = dict(
id = item.get('idx'),
quantity = item.get('qty'),
unit_price = item.get('rate'),
product_tax_code = item.get('product_tax_category')
)
if docstatus == 1:
tax_dict.update({
'sales_tax':item.get('tax_collectable')
})
return tax_dict
def set_sales_tax(doc, method):
if not TAXJAR_CALCULATE_TAX:
return
@@ -164,6 +171,9 @@ def set_sales_tax(doc, method):
setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD])
return
# check if delivering within a nexus
check_for_nexus(doc, tax_dict)
tax_data = validate_tax_request(tax_dict)
if tax_data is not None:
if not tax_data.amount_to_collect:
@@ -191,6 +201,17 @@ def set_sales_tax(doc, method):
doc.run_method("calculate_taxes_and_totals")
def check_for_nexus(doc, tax_dict):
if not frappe.db.get_value('TaxJar Nexus', {'region_code': tax_dict["to_state"]}):
for item in doc.get("items"):
item.tax_collectable = flt(0)
item.taxable_amount = flt(0)
for tax in doc.taxes:
if tax.account_head == TAX_ACCOUNT_HEAD:
doc.taxes.remove(tax)
return
def check_sales_tax_exemption(doc):
# if the party is exempt from sales tax, then set all tax account heads to zero
sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Marketplace\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Payments\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]",
"creation": "2020-08-20 19:30:48.138801",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "integration",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "ERPNext Integrations",
"links": [
{
@@ -119,15 +112,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:58.740246",
"modified": "2021-08-05 12:15:58.740247",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "ERPNext Integrations",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Integrations Settings\", \"col\": 4}}]",
"creation": "2020-07-31 10:38:54.021237",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "setting",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "ERPNext Integrations Settings",
"links": [
{
@@ -81,15 +74,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:15:58.951704",
"modified": "2021-08-05 12:15:58.951705",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "ERPNext Integrations Settings",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -250,6 +250,7 @@ doc_events = {
"validate": "erpnext.regional.india.utils.validate_tax_category"
},
"Sales Invoice": {
"after_insert": "erpnext.regional.saudi_arabia.utils.create_qr_code",
"on_submit": [
"erpnext.regional.create_transaction_log",
"erpnext.regional.italy.utils.sales_invoice_on_submit",
@@ -259,7 +260,10 @@ doc_events = {
"erpnext.regional.italy.utils.sales_invoice_on_cancel",
"erpnext.erpnext_integrations.taxjar_integration.delete_transaction"
],
"on_trash": "erpnext.regional.check_deletion_permission",
"on_trash": [
"erpnext.regional.check_deletion_permission",
"erpnext.regional.saudi_arabia.utils.delete_qr_code_file"
],
"validate": [
"erpnext.regional.india.utils.validate_document_name",
"erpnext.regional.india.utils.update_taxable_values"

View File

@@ -74,7 +74,6 @@ class TestDailyWorkSummary(unittest.TestCase):
from `tabEmail Queue` as q, `tabEmail Queue Recipient` as r \
where q.name = r.parent""", as_dict=1)
frappe.db.commit()
def setup_groups(self, hour=None):
# setup email to trigger at this hour

View File

@@ -10,6 +10,26 @@ frappe.ui.form.on('Expense Claim', {
},
company: function(frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
var expenses = frm.doc.expenses;
for (var i = 0; i < expenses.length; i++) {
var expense = expenses[i];
if (!expense.expense_type) {
continue;
}
frappe.call({
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
args: {
"expense_claim_type": expense.expense_type,
"company": frm.doc.company
},
callback: function(r) {
if (r.message) {
expense.default_account = r.message.account;
expense.cost_center = r.message.cost_center;
}
}
});
}
},
});

View File

@@ -97,7 +97,7 @@ class ShiftType(Document):
assigned_employees = [x[0] for x in assigned_employees]
if consider_default_shift:
filters = {'default_shift': self.name}
filters = {'default_shift': self.name, 'status': ['!=', 'Inactive']}
default_shift_employees = frappe.get_all('Employee', 'name', filters, as_list=True)
default_shift_employees = [x[0] for x in default_shift_employees]
return list(set(assigned_employees+default_shift_employees))

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Outgoing Salary",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Human Resource\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Outgoing Salary\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Employee\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Leave Application\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Job Applicant\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Monthly Attendance Sheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Employee\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Employee Lifecycle\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Shift Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Leaves\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Attendance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Expense Claims\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Fleet Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Recruitment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loans\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Training\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Performance\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Key Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Other Reports\", \"col\": 4}}]",
"creation": "2020-03-02 15:48:58.322521",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "hr",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "HR",
"links": [
{
@@ -942,15 +935,12 @@
"type": "Link"
}
],
"modified": "2021-08-31 12:18:59.842918",
"modified": "2021-08-31 12:18:59.842919",
"modified_by": "Administrator",
"module": "HR",
"name": "HR",
"onboarding": "Human Resource",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -334,7 +334,6 @@
},
{
"depends_on": "eval:doc.is_secured_loan",
"fetch_from": "loan_application.maximum_loan_amount",
"fieldname": "maximum_loan_amount",
"fieldtype": "Currency",
"label": "Maximum Loan Amount",
@@ -360,7 +359,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-04-19 18:10:32.360818",
"modified": "2021-10-12 18:10:32.360818",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",

View File

@@ -137,16 +137,23 @@ class Loan(AccountsController):
frappe.throw(_("Loan amount is mandatory"))
def link_loan_security_pledge(self):
if self.is_secured_loan:
loan_security_pledge = frappe.db.get_value('Loan Security Pledge', {'loan_application': self.loan_application},
'name')
if self.is_secured_loan and self.loan_application:
maximum_loan_value = frappe.db.get_value('Loan Security Pledge',
{
'loan_application': self.loan_application,
'status': 'Requested'
},
'sum(maximum_loan_value)'
)
if loan_security_pledge:
frappe.db.set_value('Loan Security Pledge', loan_security_pledge, {
'loan': self.name,
'status': 'Pledged',
'pledge_time': now_datetime()
})
if maximum_loan_value:
frappe.db.sql("""
UPDATE `tabLoan Security Pledge`
SET loan = %s, pledge_time = %s, status = 'Pledged'
WHERE status = 'Requested' and loan_application = %s
""", (self.name, now_datetime(), self.loan_application))
self.db_set('maximum_loan_amount', maximum_loan_value)
def unlink_loan_security_pledge(self):
pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name})

View File

@@ -130,10 +130,11 @@ class LoanApplication(Document):
def create_loan(source_name, target_doc=None, submit=0):
def update_accounts(source_doc, target_doc, source_parent):
account_details = frappe.get_all("Loan Type",
fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"],
filters = {'name': source_doc.loan_type}
)[0]
fields=["mode_of_payment", "payment_account","loan_account", "interest_income_account", "penalty_income_account"],
filters = {'name': source_doc.loan_type})[0]
if source_doc.is_secured_loan:
target_doc.maximum_loan_amount = 0
target_doc.mode_of_payment = account_details.mode_of_payment
target_doc.payment_account = account_details.payment_account

View File

@@ -198,7 +198,7 @@ def get_disbursal_amount(loan, on_current_security_price=0):
security_value = get_total_pledged_security_value(loan)
if loan_details.is_secured_loan and not on_current_security_price:
security_value = flt(loan_details.maximum_loan_amount)
security_value = get_maximum_amount_as_per_pledged_security(loan)
if not security_value and not loan_details.is_secured_loan:
security_value = flt(loan_details.loan_amount)
@@ -209,3 +209,6 @@ def get_disbursal_amount(loan, on_current_security_price=0):
disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount
return disbursal_amount
def get_maximum_amount_as_per_pledged_security(loan):
return flt(frappe.db.get_value('Loan Security Pledge', {'loan': loan}, 'sum(maximum_loan_value)'))

View File

@@ -411,7 +411,7 @@ def get_amounts(amounts, against_loan, posting_date):
if due_date and not final_due_date:
final_due_date = add_days(due_date, loan_type_details.grace_period_in_days)
if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested', 'Closed'):
if against_loan_doc.status in ('Disbursed', 'Closed') or against_loan_doc.disbursed_amount >= against_loan_doc.loan_amount:
pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \
- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
else:

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Loan Application\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Loan\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Processes\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Disbursement and Repayment\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Security\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
"creation": "2020-03-12 16:35:55.299820",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "loan",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Loans",
"links": [
{
@@ -245,15 +238,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:18:13.350904",
"modified": "2021-08-05 12:18:13.350905",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loans",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -1133,8 +1133,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
query_filters["has_variants"] = 0
if filters and filters.get("is_stock_item"):
or_cond_filters["is_stock_item"] = 1
or_cond_filters["has_variants"] = 1
query_filters["is_stock_item"] = 1
return frappe.get_list("Item",
fields = fields, filters=query_filters,

View File

@@ -4,13 +4,14 @@
import unittest
from collections import deque
from functools import partial
import frappe
from frappe.test_runner import make_test_records
from frappe.utils import cstr, flt
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.manufacturing.doctype.bom.bom import make_variant_bom
from erpnext.manufacturing.doctype.bom.bom import item_query, make_variant_bom
from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
@@ -375,6 +376,16 @@ class TestBOM(unittest.TestCase):
# FG Items in Scrap/Loss Table should have Is Process Loss set
self.assertRaises(frappe.ValidationError, bom_doc.submit)
def test_bom_item_query(self):
query = partial(item_query, doctype="Item", txt="", searchfield="name", start=0, page_len=20, filters={"is_stock_item": 1})
test_items = query(txt="_Test")
filtered = query(txt="_Test Item 2")
self.assertNotEqual(len(test_items), len(filtered), msg="Item filtering showing excessive results")
self.assertTrue(0 < len(filtered) <= 3, msg="Item filtering showing excessive results")
def get_default_bom(item_code="_Test FG Item 2"):
return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1})

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Produced Quantity"
@@ -7,18 +6,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Manufacturing\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": null, \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Item\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"BOM\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Work Order\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Production Plan\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Forecasting\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Work Order Summary\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"BOM Stock Report\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Production Planning Report\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Production\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Bill of Materials\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tools\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}]",
"creation": "2020-03-02 17:11:37.032604",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "organization",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Manufacturing",
"links": [
{
@@ -304,15 +297,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:00.825741",
"modified": "2021-08-05 12:16:00.825742",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Manufacturing",
"onboarding": "Manufacturing",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "Manufacturing",
"roles": [],

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Member\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Profit Settings\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Membership\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Chapter Member\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Loan Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Grant Application\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Membership\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Volunteer\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Chapter\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Donation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Tax Exemption Certification (India)\", \"col\": 4}}]",
"creation": "2020-03-02 17:23:47.811421",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "non-profit",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Non Profit",
"links": [
{
@@ -238,15 +231,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:01.146206",
"modified": "2021-08-05 12:16:01.146207",
"modified_by": "Administrator",
"module": "Non Profit",
"name": "Non Profit",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "Non Profit",
"roles": [],

View File

@@ -246,7 +246,7 @@ erpnext.patches.v13_0.update_payment_terms_outstanding
erpnext.patches.v12_0.add_state_code_for_ladakh
erpnext.patches.v13_0.item_reposting_for_incorrect_sl_and_gl
erpnext.patches.v13_0.delete_old_bank_reconciliation_doctypes
erpnext.patches.v12_0.update_vehicle_no_reqd_condition
erpnext.patches.v13_0.update_vehicle_no_reqd_condition
erpnext.patches.v13_0.setup_fields_for_80g_certificate_and_donation
erpnext.patches.v13_0.rename_membership_settings_to_non_profit_settings
erpnext.patches.v13_0.setup_gratuity_rule_for_india_and_uae
@@ -286,6 +286,8 @@ erpnext.patches.v13_0.shopify_deprecation_warning
erpnext.patches.v13_0.migrate_stripe_api
erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries
erpnext.patches.v13_0.einvoicing_deprecation_warning
execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings")
execute:frappe.reload_doc("erpnext_integrations", "doctype", "Product Tax Category")
erpnext.patches.v13_0.custom_fields_for_taxjar_integration
erpnext.patches.v14_0.delete_einvoicing_doctypes
erpnext.patches.v13_0.set_operation_time_based_on_operating_cost
@@ -299,7 +301,9 @@ erpnext.patches.v13_0.gst_fields_for_pos_invoice
erpnext.patches.v13_0.create_accounting_dimensions_in_pos_doctypes
erpnext.patches.v13_0.trim_sales_invoice_custom_field_length
erpnext.patches.v13_0.create_custom_field_for_finance_book
erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries
erpnext.patches.v13_0.modify_invalid_gain_loss_gl_entries #2
erpnext.patches.v13_0.fix_additional_cost_in_mfg_stock_entry
erpnext.patches.v13_0.set_status_in_maintenance_schedule_table
erpnext.patches.v13_0.add_default_interview_notification_templates
erpnext.patches.v13_0.add_default_interview_notification_templates
erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
erpnext.patches.v13_0.requeue_failed_reposts

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.regional.united_states.setup import add_permissions
from erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings import add_permissions
def execute():
@@ -11,7 +11,12 @@ def execute():
if not company:
return
frappe.reload_doc("regional", "doctype", "product_tax_category")
TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox")
if (not TAXJAR_CREATE_TRANSACTIONS and not TAXJAR_CALCULATE_TAX and not TAXJAR_SANDBOX_MODE):
return
custom_fields = {
'Sales Invoice Item': [
@@ -29,4 +34,4 @@ def execute():
}
create_custom_fields(custom_fields, update=True)
add_permissions()
frappe.enqueue('erpnext.regional.united_states.setup.add_product_tax_categories', now=True)
frappe.enqueue('erpnext.erpnext_integrations.doctype.taxjar_settings.taxjar_settings.add_product_tax_categories', now=True)

View File

@@ -0,0 +1,8 @@
import frappe
def execute():
frappe.reload_doc('core', 'doctype', 'scheduled_job_type')
if frappe.db.exists('Scheduled Job Type', 'repost_item_valuation.repost_entries'):
frappe.db.set_value('Scheduled Job Type',
'repost_item_valuation.repost_entries', 'stopped', 0)

View File

@@ -17,7 +17,7 @@ def execute():
where
ref_exchange_rate = 1
and docstatus = 1
and ifnull(exchange_gain_loss, '') != ''
and ifnull(exchange_gain_loss, 0) != 0
group by
parent
""", as_dict=1)
@@ -30,7 +30,7 @@ def execute():
where
ref_exchange_rate = 1
and docstatus = 1
and ifnull(exchange_gain_loss, '') != ''
and ifnull(exchange_gain_loss, 0) != 0
group by
parent
""", as_dict=1)
@@ -38,12 +38,24 @@ def execute():
if purchase_invoices + sales_invoices:
frappe.log_error(json.dumps(purchase_invoices + sales_invoices, indent=2), title="Patch Log")
acc_frozen_upto = frappe.db.get_value('Accounts Settings', None, 'acc_frozen_upto')
if acc_frozen_upto:
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None)
for invoice in purchase_invoices + sales_invoices:
doc = frappe.get_doc(invoice.type, invoice.name)
doc.docstatus = 2
doc.make_gl_entries()
for advance in doc.advances:
if advance.ref_exchange_rate == 1:
advance.db_set('exchange_gain_loss', 0, False)
doc.docstatus = 1
doc.make_gl_entries()
try:
doc = frappe.get_doc(invoice.type, invoice.name)
doc.docstatus = 2
doc.make_gl_entries()
for advance in doc.advances:
if advance.ref_exchange_rate == 1:
advance.db_set('exchange_gain_loss', 0, False)
doc.docstatus = 1
doc.make_gl_entries()
frappe.db.commit()
except Exception:
frappe.db.rollback()
print(f'Failed to correct gl entries of {invoice.name}')
if acc_frozen_upto:
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', acc_frozen_upto)

View File

@@ -0,0 +1,13 @@
import frappe
from frappe.utils import cstr
def execute():
reposts = frappe.get_all("Repost Item Valuation",
{"status": "Failed", "modified": [">", "2021-10-05"] },
["name", "modified", "error_log"])
for repost in reposts:
if "check_freezing_date" in cstr(repost.error_log):
frappe.db.set_value("Repost Item Valuation", repost.name, "status", "Queued")

View File

@@ -2,7 +2,7 @@ import frappe
def execute():
frappe.reload_doc('custom', 'doctype', 'custom_field')
frappe.reload_doc('custom', 'doctype', 'custom_field', force=True)
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
return

View File

@@ -329,7 +329,7 @@
{
"fieldname": "earning_deduction",
"fieldtype": "Section Break",
"label": "Earning & Deduction",
"label": "Earnings & Deductions",
"oldfieldtype": "Section Break"
},
{
@@ -380,7 +380,7 @@
"depends_on": "total_loan_repayment",
"fieldname": "loan_repayment",
"fieldtype": "Section Break",
"label": "Loan repayment"
"label": "Loan Repayment"
},
{
"fieldname": "loans",
@@ -425,7 +425,7 @@
{
"fieldname": "net_pay_info",
"fieldtype": "Section Break",
"label": "net pay info"
"label": "Net Pay Info"
},
{
"fieldname": "net_pay",
@@ -647,7 +647,7 @@
"idx": 9,
"is_submittable": 1,
"links": [],
"modified": "2021-09-01 10:35:52.374549",
"modified": "2021-10-08 11:47:47.098248",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Slip",

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Outgoing Salary",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Payroll\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Outgoing Salary\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Structure\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Payroll Entry\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Slip\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Income Tax Slab\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Salary Register\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Payroll\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Taxation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Compensations\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
"creation": "2020-05-27 19:54:23.405607",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "money-coins-1",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Payroll",
"links": [
{
@@ -343,11 +336,8 @@
"modified_by": "Administrator",
"module": "Payroll",
"name": "Payroll",
"onboarding": "Payroll",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -1,5 +1,4 @@
{
"category": "",
"charts": [
{
"chart_name": "Project Summary",
@@ -8,18 +7,12 @@
],
"content": "[{\"type\": \"chart\", \"data\": {\"chart_name\": \"Open Projects\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Task\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Project\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Timesheet\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Project Billing Summary\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Projects\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Time Tracking\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
"creation": "2020-03-02 15:46:04.874669",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "project",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Projects",
"links": [
{
@@ -201,15 +194,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:01.540145",
"modified": "2021-08-05 12:16:01.540147",
"modified_by": "Administrator",
"module": "Projects",
"name": "Projects",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -5,7 +5,7 @@ const docsUrl = "https://erpnext.com/docs/";
frappe.help.help_links["Form/Rename Tool"] = [
{
label: "Bulk Rename",
url: docsUrl + "user/manual/en/setting-up/data/bulk-rename",
url: docsUrl + "user/manual/en/using-erpnext/articles/bulk-rename",
},
];
@@ -59,10 +59,23 @@ frappe.help.help_links["Form/System Settings"] = [
},
];
frappe.help.help_links["data-import-tool"] = [
frappe.help.help_links["Form/Data Import"] = [
{
label: "Importing and Exporting Data",
url: docsUrl + "user/manual/en/setting-up/data/data-import-tool",
url: docsUrl + "user/manual/en/setting-up/data/data-import",
},
{
label: "Overwriting Data from Data Import Tool",
url:
docsUrl +
"user/manual/en/setting-up/articles/overwriting-data-from-data-import-tool",
},
];
frappe.help.help_links["List/Data Import"] = [
{
label: "Importing and Exporting Data",
url: docsUrl + "user/manual/en/setting-up/data/data-import",
},
{
label: "Overwriting Data from Data Import Tool",
@@ -101,14 +114,14 @@ frappe.help.help_links["Form/Global Defaults"] = [
},
];
frappe.help.help_links["Form/Email Digest"] = [
frappe.help.help_links["List/Print Heading"] = [
{
label: "Email Digest",
url: docsUrl + "user/manual/en/setting-up/email/email-digest",
label: "Print Heading",
url: docsUrl + "user/manual/en/setting-up/print/print-headings",
},
];
frappe.help.help_links["List/Print Heading"] = [
frappe.help.help_links["Form/Print Heading"] = [
{
label: "Print Heading",
url: docsUrl + "user/manual/en/setting-up/print/print-headings",
@@ -153,18 +166,25 @@ frappe.help.help_links["List/Email Account"] = [
frappe.help.help_links["List/Notification"] = [
{
label: "Notification",
url: docsUrl + "user/manual/en/setting-up/email/notifications",
url: docsUrl + "user/manual/en/setting-up/notifications",
},
];
frappe.help.help_links["Form/Notification"] = [
{
label: "Notification",
url: docsUrl + "user/manual/en/setting-up/email/notifications",
url: docsUrl + "user/manual/en/setting-up/notifications",
},
];
frappe.help.help_links["List/Email Digest"] = [
frappe.help.help_links["Form/Email Digest"] = [
{
label: "Email Digest",
url: docsUrl + "user/manual/en/setting-up/email/email-digest",
},
];
frappe.help.help_links["Form/Email Digest"] = [
{
label: "Email Digest",
url: docsUrl + "user/manual/en/setting-up/email/email-digest",
@@ -174,7 +194,7 @@ frappe.help.help_links["List/Email Digest"] = [
frappe.help.help_links["List/Auto Email Report"] = [
{
label: "Auto Email Reports",
url: docsUrl + "user/manual/en/setting-up/email/email-reports",
url: docsUrl + "user/manual/en/setting-up/email/auto-email-reports",
},
];
@@ -188,14 +208,7 @@ frappe.help.help_links["Form/Print Settings"] = [
frappe.help.help_links["print-format-builder"] = [
{
label: "Print Format Builder",
url: docsUrl + "user/manual/en/setting-up/print/print-settings",
},
];
frappe.help.help_links["List/Print Heading"] = [
{
label: "Print Heading",
url: docsUrl + "user/manual/en/setting-up/print/print-headings",
url: docsUrl + "user/manual/en/setting-up/print/print-format-builder",
},
];
@@ -315,7 +328,7 @@ frappe.help.help_links["Form/Sales Order"] = [
},
{
label: "Recurring Sales Order",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
{
label: "Applying Discount",
@@ -344,14 +357,14 @@ frappe.help.help_links["Form/Sales Order"] = [
frappe.help.help_links["Form/Product Bundle"] = [
{
label: "Product Bundle",
url: docsUrl + "user/manual/en/selling/setup/product-bundle",
url: docsUrl + "user/manual/en/selling/product-bundle",
},
];
frappe.help.help_links["Form/Selling Settings"] = [
{
label: "Selling Settings",
url: docsUrl + "user/manual/en/selling/setup/selling-settings",
url: docsUrl + "user/manual/en/selling/selling-settings",
},
];
@@ -397,7 +410,7 @@ frappe.help.help_links["List/Purchase Order"] = [
},
{
label: "Recurring Purchase Order",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
];
@@ -420,7 +433,7 @@ frappe.help.help_links["Form/Purchase Order"] = [
},
{
label: "Recurring Purchase Order",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
{
label: "Subcontracting",
@@ -435,24 +448,17 @@ frappe.help.help_links["List/Purchase Taxes and Charges Template"] = [
},
];
frappe.help.help_links["List/POS Profile"] = [
{
label: "POS Profile",
url: docsUrl + "user/manual/en/setting-up/pos-setting",
},
];
frappe.help.help_links["List/Price List"] = [
{
label: "Price List",
url: docsUrl + "user/manual/en/setting-up/price-lists",
url: docsUrl + "user/manual/en/stock/price-lists",
},
];
frappe.help.help_links["List/Authorization Rule"] = [
{
label: "Authorization Rule",
url: docsUrl + "user/manual/en/setting-up/authorization-rule",
url: docsUrl + "user/manual/en/customize-erpnext/authorization-rule",
},
];
@@ -468,27 +474,14 @@ frappe.help.help_links["List/Stock Reconciliation"] = [
label: "Stock Reconciliation",
url:
docsUrl +
"user/manual/en/setting-up/stock-reconciliation-for-non-serialized-item",
"user/manual/en/stock/stock-reconciliation",
},
];
frappe.help.help_links["Tree/Territory"] = [
{
label: "Territory",
url: docsUrl + "user/manual/en/setting-up/territory",
},
];
frappe.help.help_links["Form/Dropbox Backup"] = [
{
label: "Dropbox Backup",
url: docsUrl + "user/manual/en/setting-up/third-party-backups",
},
{
label: "Setting Up Dropbox Backup",
url:
docsUrl +
"user/manual/en/setting-up/articles/setting-up-dropbox-backups",
url: docsUrl + "user/manual/en/selling/territory",
},
];
@@ -501,12 +494,6 @@ frappe.help.help_links["List/Company"] = [
label: "Company",
url: docsUrl + "user/manual/en/setting-up/company-setup",
},
{
label: "Managing Multiple Companies",
url:
docsUrl +
"user/manual/en/setting-up/articles/managing-multiple-companies",
},
{
label: "Delete All Related Transactions for a Company",
url:
@@ -517,21 +504,6 @@ frappe.help.help_links["List/Company"] = [
//Accounts
frappe.help.help_links["modules/Accounts"] = [
{
label: "Introduction to Accounts",
url: docsUrl + "user/manual/en/accounts/",
},
{
label: "Chart of Accounts",
url: docsUrl + "user/manual/en/accounts/chart-of-accounts.html",
},
{
label: "Multi Currency Accounting",
url: docsUrl + "user/manual/en/accounts/multi-currency-accounting",
},
];
frappe.help.help_links["Tree/Account"] = [
{
label: "Chart of Accounts",
@@ -560,7 +532,7 @@ frappe.help.help_links["Form/Sales Invoice"] = [
},
{
label: "Recurring Sales Invoice",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
];
@@ -571,7 +543,7 @@ frappe.help.help_links["List/Sales Invoice"] = [
},
{
label: "Accounts Opening Balance",
url: docsUrl + "user/manual/en/accounts/opening-accounts",
url: docsUrl + "user/manual/en/accounts/opening-balances",
},
{
label: "Sales Return",
@@ -579,21 +551,28 @@ frappe.help.help_links["List/Sales Invoice"] = [
},
{
label: "Recurring Sales Invoice",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
];
frappe.help.help_links["pos"] = [
frappe.help.help_links["point-of-sale"] = [
{
label: "Point of Sale Invoice",
url: docsUrl + "user/manual/en/accounts/point-of-sale-pos-invoice",
url: docsUrl + "user/manual/en/accounts/point-of-sales",
},
];
frappe.help.help_links["List/POS Profile"] = [
{
label: "Point of Sale Profile",
url: docsUrl + "user/manual/en/setting-up/pos-setting",
url: docsUrl + "user/manual/en/accounts/pos-profile",
},
];
frappe.help.help_links["Form/POS Profile"] = [
{
label: "POS Profile",
url: docsUrl + "user/manual/en/accounts/pos-profile",
},
];
@@ -604,11 +583,11 @@ frappe.help.help_links["List/Purchase Invoice"] = [
},
{
label: "Accounts Opening Balance",
url: docsUrl + "user/manual/en/accounts/opening-accounts",
url: docsUrl + "user/manual/en/accounts/opening-balance",
},
{
label: "Recurring Purchase Invoice",
url: docsUrl + "user/manual/en/accounts/recurring-orders-and-invoices",
url: docsUrl + "user/manual/en/accounts/articles/recurring-orders-and-invoices",
},
];
@@ -623,7 +602,7 @@ frappe.help.help_links["List/Journal Entry"] = [
},
{
label: "Accounts Opening Balance",
url: docsUrl + "user/manual/en/accounts/opening-accounts",
url: docsUrl + "user/manual/en/accounts/opening-balance",
},
];
@@ -644,7 +623,7 @@ frappe.help.help_links["List/Payment Request"] = [
frappe.help.help_links["List/Asset"] = [
{
label: "Managing Fixed Assets",
url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
url: docsUrl + "user/manual/en/asset",
},
];
@@ -659,6 +638,8 @@ frappe.help.help_links["Tree/Cost Center"] = [
{ label: "Budgeting", url: docsUrl + "user/manual/en/accounts/budgeting" },
];
//Stock
frappe.help.help_links["List/Item"] = [
{ label: "Item", url: docsUrl + "user/manual/en/stock/item" },
{
@@ -676,7 +657,7 @@ frappe.help.help_links["List/Item"] = [
},
{
label: "Managing Fixed Assets",
url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
url: docsUrl + "user/manual/en/asset",
},
{
label: "Item Codification",
@@ -711,7 +692,7 @@ frappe.help.help_links["Form/Item"] = [
},
{
label: "Managing Fixed Assets",
url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
url: docsUrl + "user/manual/en/asset",
},
{
label: "Item Codification",
@@ -771,10 +752,6 @@ frappe.help.help_links["Form/Delivery Note"] = [
url:
docsUrl + "user/manual/en/stock/articles/track-items-using-barcode",
},
{
label: "Subcontracting",
url: docsUrl + "user/manual/en/manufacturing/subcontracting",
},
];
frappe.help.help_links["List/Installation Note"] = [
@@ -784,21 +761,10 @@ frappe.help.help_links["List/Installation Note"] = [
},
];
frappe.help.help_links["Tree"] = [
{
label: "Managing Tree Structure Masters",
url:
docsUrl +
"user/manual/en/setting-up/articles/managing-tree-structure-masters",
},
];
frappe.help.help_links["List/Budget"] = [
{ label: "Budgeting", url: docsUrl + "user/manual/en/accounts/budgeting" },
];
//Stock
frappe.help.help_links["List/Material Request"] = [
{
label: "Material Request",
@@ -861,6 +827,10 @@ frappe.help.help_links["Form/Serial No"] = [
{ label: "Serial No", url: docsUrl + "user/manual/en/stock/serial-no" },
];
frappe.help.help_links["List/Batch"] = [
{ label: "Batch", url: docsUrl + "user/manual/en/stock/batch" },
];
frappe.help.help_links["Form/Batch"] = [
{ label: "Batch", url: docsUrl + "user/manual/en/stock/batch" },
];
@@ -868,35 +838,35 @@ frappe.help.help_links["Form/Batch"] = [
frappe.help.help_links["Form/Packing Slip"] = [
{
label: "Packing Slip",
url: docsUrl + "user/manual/en/stock/tools/packing-slip",
url: docsUrl + "user/manual/en/stock/packing-slip",
},
];
frappe.help.help_links["Form/Quality Inspection"] = [
{
label: "Quality Inspection",
url: docsUrl + "user/manual/en/stock/tools/quality-inspection",
url: docsUrl + "user/manual/en/stock/quality-inspection",
},
];
frappe.help.help_links["Form/Landed Cost Voucher"] = [
{
label: "Landed Cost Voucher",
url: docsUrl + "user/manual/en/stock/tools/landed-cost-voucher",
url: docsUrl + "user/manual/en/stock/landed-cost-voucher",
},
];
frappe.help.help_links["Tree/Item Group"] = [
{
label: "Item Group",
url: docsUrl + "user/manual/en/stock/setup/item-group",
url: docsUrl + "user/manual/en/stock/item-group",
},
];
frappe.help.help_links["Form/Item Attribute"] = [
{
label: "Item Attribute",
url: docsUrl + "user/manual/en/stock/setup/item-attribute",
url: docsUrl + "user/manual/en/stock/item-attribute",
},
];
@@ -911,7 +881,7 @@ frappe.help.help_links["Form/UOM"] = [
frappe.help.help_links["Form/Stock Reconciliation"] = [
{
label: "Opening Stock Entry",
url: docsUrl + "user/manual/en/stock/opening-stock",
url: docsUrl + "user/manual/en/stock/stock-reconciliation",
},
];
@@ -938,13 +908,13 @@ frappe.help.help_links["Form/Newsletter"] = [
];
frappe.help.help_links["Form/Campaign"] = [
{ label: "Campaign", url: docsUrl + "user/manual/en/CRM/setup/campaign" },
{ label: "Campaign", url: docsUrl + "user/manual/en/CRM/campaign" },
];
frappe.help.help_links["Tree/Sales Person"] = [
{
label: "Sales Person",
url: docsUrl + "user/manual/en/CRM/setup/sales-person",
url: docsUrl + "user/manual/en/CRM/sales-person",
},
];
@@ -953,30 +923,13 @@ frappe.help.help_links["Form/Sales Person"] = [
label: "Sales Person Target",
url:
docsUrl +
"user/manual/en/selling/setup/sales-person-target-allocation",
"user/manual/en/selling/sales-person-target-allocation",
},
];
//Support
frappe.help.help_links["List/Feedback Trigger"] = [
{
label: "Feedback Trigger",
url: docsUrl + "user/manual/en/setting-up/feedback/setting-up-feedback",
},
];
frappe.help.help_links["List/Feedback Request"] = [
{
label: "Feedback Request",
url: docsUrl + "user/manual/en/setting-up/feedback/submit-feedback",
},
];
frappe.help.help_links["List/Feedback Request"] = [
{
label: "Feedback Request",
url: docsUrl + "user/manual/en/setting-up/feedback/submit-feedback",
label: "Sales Person in Transactions",
url:
docsUrl +
"user/manual/en/selling/articles/sales-persons-in-the-sales-transactions",
},
];
@@ -1019,7 +972,7 @@ frappe.help.help_links["Form/Operation"] = [
frappe.help.help_links["Form/BOM Update Tool"] = [
{
label: "BOM Update Tool",
url: docsUrl + "user/manual/en/manufacturing/tools/bom-update-tool",
url: docsUrl + "user/manual/en/manufacturing/bom-update-tool",
},
];
@@ -1036,7 +989,7 @@ frappe.help.help_links["Form/Customize Form"] = [
},
];
frappe.help.help_links["Form/Custom Field"] = [
frappe.help.help_links["List/Custom Field"] = [
{
label: "Custom Field",
url: docsUrl + "user/manual/en/customize-erpnext/custom-field",

View File

@@ -334,10 +334,12 @@ erpnext.HierarchyChart = class {
if (child_nodes) {
$.each(child_nodes, (_i, data) => {
this.add_node(node, data);
setTimeout(() => {
this.add_connector(node.id, data.id);
}, 250);
if (!$(`[id="${data.id}"]`).length) {
this.add_node(node, data);
setTimeout(() => {
this.add_connector(node.id, data.id);
}, 250);
}
});
}
}

View File

@@ -1,20 +1,13 @@
{
"category": "",
"charts": [],
"content": "[{\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Goal\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Procedure\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Inspection\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Review\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Quality Action\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Non Conformance\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Goal and Procedure\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Feedback\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Meeting\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Review and Action\", \"col\": 4}}]",
"creation": "2020-03-02 15:49:28.632014",
"developer_mode_only": 0,
"disable_user_customization": 0,
"docstatus": 0,
"doctype": "Workspace",
"extends": "",
"extends_another_page": 0,
"for_user": "",
"hide_custom": 0,
"icon": "quality",
"idx": 0,
"is_default": 0,
"is_standard": 0,
"label": "Quality",
"links": [
{
@@ -149,15 +142,12 @@
"type": "Link"
}
],
"modified": "2021-08-05 12:16:01.699912",
"modified": "2021-08-05 12:16:01.699913",
"modified_by": "Administrator",
"module": "Quality Management",
"name": "Quality",
"onboarding": "",
"owner": "Administrator",
"parent_page": "",
"pin_to_bottom": 0,
"pin_to_top": 0,
"public": 1,
"restrict_to_domain": "",
"roles": [],

View File

@@ -31,3 +31,4 @@ def create_transaction_log(doc, method):
"document_name": doc.name,
"data": data
}).insert(ignore_permissions=True)

View File

@@ -6,8 +6,10 @@
"engine": "InnoDB",
"field_order": [
"gst_summary",
"column_break_2",
"gst_tax_settings_section",
"round_off_gst_values",
"column_break_4",
"hsn_wise_tax_breakup",
"gstin_email_sent_on",
"section_break_4",
"gst_accounts",
@@ -17,37 +19,23 @@
{
"fieldname": "gst_summary",
"fieldtype": "HTML",
"label": "GST Summary",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
"label": "GST Summary"
},
{
"fieldname": "gstin_email_sent_on",
"fieldtype": "Date",
"label": "GSTIN Email Sent On",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
"read_only": 1
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"show_days": 1,
"show_seconds": 1
"fieldtype": "Section Break"
},
{
"fieldname": "gst_accounts",
"fieldtype": "Table",
"label": "GST Accounts",
"options": "GST Account",
"show_days": 1,
"show_seconds": 1
"options": "GST Account"
},
{
"default": "250000",
@@ -56,24 +44,35 @@
"fieldtype": "Data",
"in_list_view": 1,
"label": "B2C Limit",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"default": "0",
"description": "Enabling this option will round off individual GST components in all the Invoices",
"fieldname": "round_off_gst_values",
"fieldtype": "Check",
"label": "Round Off GST Values",
"show_days": 1,
"show_seconds": 1
"label": "Round Off GST Values"
},
{
"default": "0",
"fieldname": "hsn_wise_tax_breakup",
"fieldtype": "Check",
"label": "Tax Breakup Table Based On HSN Code"
},
{
"fieldname": "gst_tax_settings_section",
"fieldtype": "Section Break",
"label": "GST Tax Settings"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-01-28 17:19:47.969260",
"modified": "2021-10-11 18:10:14.242614",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Settings",
@@ -83,4 +82,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
}

View File

@@ -0,0 +1,49 @@
{
"actions": [],
"creation": "2021-07-13 09:17:09.862163",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"title",
"item_tax_template",
"account"
],
"fields": [
{
"fieldname": "account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1
},
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1
},
{
"fieldname": "item_tax_template",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Tax Template",
"options": "Item Tax Template",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-08-04 06:42:38.205597",
"modified_by": "Administrator",
"module": "Regional",
"name": "KSA VAT Purchase Account",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Havenir Solutions and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class KSAVATPurchaseAccount(Document):
pass

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2021, Havenir Solutions and contributors
// For license information, please see license.txt
frappe.ui.form.on('KSA VAT Sales Account', {
// refresh: function(frm) {
// }
});

View File

@@ -0,0 +1,49 @@
{
"actions": [],
"creation": "2021-07-13 08:46:33.820968",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"title",
"item_tax_template",
"account"
],
"fields": [
{
"fieldname": "account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1
},
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1
},
{
"fieldname": "item_tax_template",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Tax Template",
"options": "Item Tax Template",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-08-04 06:42:00.081407",
"modified_by": "Administrator",
"module": "Regional",
"name": "KSA VAT Sales Account",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Havenir Solutions and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class KSAVATSalesAccount(Document):
pass

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Havenir Solutions and Contributors
# See license.txt
# import frappe
import unittest
class TestKSAVATSalesAccount(unittest.TestCase):
pass

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2021, Havenir Solutions and contributors
// For license information, please see license.txt
frappe.ui.form.on('KSA VAT Setting', {
onload: function () {
frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting');
}
});

View File

@@ -0,0 +1,49 @@
{
"actions": [],
"autoname": "field:company",
"creation": "2021-07-13 08:49:01.100356",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"ksa_vat_sales_accounts",
"ksa_vat_purchase_accounts"
],
"fields": [
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1,
"unique": 1
},
{
"fieldname": "ksa_vat_sales_accounts",
"fieldtype": "Table",
"label": "KSA VAT Sales Accounts",
"options": "KSA VAT Sales Account",
"reqd": 1
},
{
"fieldname": "ksa_vat_purchase_accounts",
"fieldtype": "Table",
"label": "KSA VAT Purchase Accounts",
"options": "KSA VAT Purchase Account",
"reqd": 1
}
],
"links": [],
"modified": "2021-08-26 04:29:06.499378",
"modified_by": "Administrator",
"module": "Regional",
"name": "KSA VAT Setting",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "company",
"track_changes": 1
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Havenir Solutions and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class KSAVATSetting(Document):
pass

View File

@@ -0,0 +1,5 @@
frappe.listview_settings['KSA VAT Setting'] = {
onload () {
frappe.breadcrumbs.add('Accounts');
}
}

View File

@@ -0,0 +1,9 @@
# Copyright (c) 2021, Havenir Solutions and Contributors
# See license.txt
# import frappe
import unittest
class TestKSAVATSetting(unittest.TestCase):
pass

View File

@@ -112,7 +112,11 @@ def validate_gstin_check_digit(gstin, label='GSTIN'):
frappe.throw(_("""Invalid {0}! The check digit validation has failed. Please ensure you've typed the {0} correctly.""").format(label))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
return [_("Item"), _("Taxable Amount")] + tax_accounts
hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
if frappe.get_meta(item_doctype).has_field('gst_hsn_code') and hsn_wise_in_gst_settings:
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts
else:
return [_("Item"), _("Taxable Amount")] + tax_accounts
def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
itemised_tax = get_itemised_tax(doc.taxes, with_tax_account=account_wise)
@@ -122,14 +126,17 @@ def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
if not frappe.get_meta(doc.doctype + " Item").has_field('gst_hsn_code'):
return itemised_tax, itemised_taxable_amount
if hsn_wise:
hsn_wise_in_gst_settings = frappe.db.get_single_value('GST Settings','hsn_wise_tax_breakup')
tax_breakup_hsn_wise = hsn_wise or hsn_wise_in_gst_settings
if tax_breakup_hsn_wise:
item_hsn_map = frappe._dict()
for d in doc.items:
item_hsn_map.setdefault(d.item_code or d.item_name, d.get("gst_hsn_code"))
hsn_tax = {}
for item, taxes in itemised_tax.items():
item_or_hsn = item if not hsn_wise else item_hsn_map.get(item)
item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
hsn_tax.setdefault(item_or_hsn, frappe._dict())
for tax_desc, tax_detail in taxes.items():
key = tax_desc
@@ -142,7 +149,7 @@ def get_itemised_tax_breakup_data(doc, account_wise=False, hsn_wise=False):
# set taxable amount
hsn_taxable_amount = frappe._dict()
for item in itemised_taxable_amount:
item_or_hsn = item if not hsn_wise else item_hsn_map.get(item)
item_or_hsn = item if not tax_breakup_hsn_wise else item_hsn_map.get(item)
hsn_taxable_amount.setdefault(item_or_hsn, 0)
hsn_taxable_amount[item_or_hsn] += itemised_taxable_amount.get(item)

View File

@@ -172,13 +172,6 @@ class Gstr1Report(object):
self.invoices = frappe._dict()
conditions = self.get_conditions()
company_gstins = get_company_gstin_number(self.filters.get('company'), all_gstins=True)
if company_gstins:
self.filters.update({
'company_gstins': company_gstins
})
invoice_data = frappe.db.sql("""
select
{select_columns}
@@ -242,7 +235,7 @@ class Gstr1Report(object):
elif self.filters.get("type_of_business") == "EXPORT":
conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
conditions += " AND IFNULL(billing_address_gstin, '') NOT IN %(company_gstins)s"
conditions += " AND IFNULL(billing_address_gstin, '') != company_gstin"
return conditions

Some files were not shown because too many files have changed in this diff Show More