Compare commits

...

691 Commits

Author SHA1 Message Date
Anurag Mishra
7539cfecd2 Merge branch 'overtime-feature' of https://github.com/anurag810/erpnext into overtime-feature 2021-08-11 15:18:08 +05:30
Anurag Mishra
18f04111d6 fix: Code optimisation 2021-08-11 15:17:42 +05:30
Anurag Mishra
b2ba9aacb2 Merge branch 'version-13-hotfix' into overtime-feature 2021-08-11 13:32:52 +05:30
Anurag Mishra
4a6694e80a fix: changes requested 2021-08-11 12:59:22 +05:30
Frappe PR Bot
f3ae956eae perf: various minor perf fixes for ledger postings (#26775) (#26896)
* perf: only validate if voucher is journal entry

* perf: optimize merge GLE

- Order fields such that comparison will fail faster
- Break out of loops if not matched

* perf: don't try to match SLE if count mismatch

* refactor: simplify initialize_previous_data

* perf: use cache for fetching valuation_method

These are set only once fields

* refactor: simplify get_future_stock_vouchers

* refactor: simplify get_voucherwise_gl_entries

* perf: fetch only required fields for GL comparison

`select *` fetches all fields, output of this function is only used for
comparing.

* perf: reorder conditions in PL cost center check

* perf: reduce query while validating new gle

* perf: use cache for validating warehouse props

These properties don't change often, no need to query everytime.

* perf: use cached stock settings to validate SLE

* docs: update misleading docstring

Co-authored-by: Marica <maricadsouza221197@gmail.com>
(cherry picked from commit 9152715f90)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-11 12:18:58 +05:30
Rucha Mahabal
fd325a123c fix(style): apply svg container margin only in desktop view (#26894) 2021-08-10 23:49:56 +05:30
Frappe PR Bot
1167a9bf94 fix: unsetting of payment if no pos profile found (#26891)
* fix: unseting of payment if no pos profile found (#26884)

(cherry picked from commit b614834efe)

# Conflicts:
#	erpnext/public/js/controllers/taxes_and_totals.js

* fix: conflicts

* fix: conflicts

* fix: conflicts

* fix: conflicts

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Co-authored-by: Afshan <afshan13k@gmail.com>
2021-08-10 23:18:23 +05:30
Anupam Kumar
a6aa6cd7d6 fix: timesheet amount issue (#25993)
* fix: timesheet amount issue

* fix: timesheet detail rate conversion

* fix: condition to check timesheet currency

* fix: removing console statement
2021-08-10 20:32:15 +05:30
Frappe PR Bot
1a39d1a311 fix: cost center & account validation in Sales/Purchase Taxes and Charges (#26881) 2021-08-10 19:38:39 +05:30
Anuja Pawar
66784a16cb fix: Sales Return cancellation if linked with Payment Entry (#26883) 2021-08-10 19:38:16 +05:30
Marica
d657f39ab8 Merge pull request #25622 from noahjacob/promo_scheme_feat
feat: added multi-select fields to create multiple pricing rules.
2021-08-10 19:09:42 +05:30
Marica
af9863146d fix: Grammar in Error message 2021-08-10 18:49:07 +05:30
Noah Jacob
49b7c7575e refactor: code cleanup 2021-08-10 18:35:46 +05:30
Noah Jacob
4ee6e32d74 test(fix): fixed test case 2021-08-10 18:34:18 +05:30
Frappe PR Bot
a7e0805039 fix(e-invoicing): cannot cancel invoice if IRN cancelled on portal (#26879) 2021-08-10 17:16:15 +05:30
Nabin Hait
f8031d3d79 Merge pull request #26261 from ruchamahabal/org-chart
feat: Organizational Chart
2021-08-10 17:12:59 +05:30
Saqib
363225d2ba fix(asset): incorrect date difference calculation (#26805) 2021-08-10 16:37:23 +05:30
Subin Tom
793063bf4e fix: pos return payment mode issue (#26875) 2021-08-10 15:57:30 +05:30
Frappe PR Bot
1ba04fdfe5 fix: pos profile not mandatory for Sales Invoice (#26876) 2021-08-10 15:47:36 +05:30
Marica
1776fc44b7 Merge pull request #26878 from marination/serial-no-space-hotfix
fix: Clean Serial No input on Server Side
2021-08-10 15:25:29 +05:30
marination
510e31952d test: Serial no sanitation 2021-08-10 14:35:51 +05:30
marination
f22b858253 fix: Clean Serial No input on Server Side 2021-08-10 14:35:41 +05:30
Marica
fd12f65047 Merge pull request #26854 from marination/asset-lcv-gl-entry-hotfix
fix: Faulty Gl Entry for Asset LCVs (#26803)
2021-08-10 14:07:12 +05:30
Saqib
5719198576 feat: dynamic conditions for applying SLA (#26806) 2021-08-10 13:56:48 +05:30
Anurag Mishra
24da00cada fix: updating lead status while customer creation (#26607)
* fix:  updating lead status while customer creation

* fix: changes requested
2021-08-10 13:17:41 +05:30
marination
06b6b7e3cc fix: Set CWIP Account in company at the start to avoid flaky test 2021-08-10 13:14:32 +05:30
Anurag Mishra
8db493b2be chore: formatting 2021-08-10 12:45:51 +05:30
Anurag Mishra
21bc752da5 fix: Removed print statement 2021-08-10 12:45:51 +05:30
Anurag Mishra
96db78f7bc fix: Test Cases 2021-08-10 12:45:51 +05:30
Anurag Mishra
32f3b24c3a fix: Test Cases 2021-08-10 12:45:51 +05:30
Anurag Mishra
10647bfcd7 fix: test 2021-08-10 12:45:51 +05:30
Anurag Mishra
7d272dc648 fix: test Payroll Entry 2021-08-10 12:45:51 +05:30
Anurag Mishra
b96165883e fix: fixed test and resolved conflicts 2021-08-10 12:45:51 +05:30
Anurag Mishra
5683857f9f fix: sider 2021-08-10 12:45:50 +05:30
Anurag Mishra
73b3121127 fix: some enhancemets and test cases 2021-08-10 12:45:50 +05:30
Anurag Mishra
769d774ccc feat: Validation, sider and form dashbord 2021-08-10 12:45:50 +05:30
Anurag Mishra
da2e95dbcc feat: Overtime based on Attendance and Timesheet 2021-08-10 12:44:50 +05:30
Anurag Mishra
3851d15360 feat:overtime 2021-08-10 12:41:45 +05:30
Anurag Mishra
e4fd6d7763 feat: Overtime 2021-08-10 12:41:45 +05:30
Anurag Mishra
8f1850b21c feat: settings for Overtime 2021-08-10 12:38:33 +05:30
Deepesh Garg
25a2f2b90e Merge pull request #26579 from deepeshgarg007/discount_accounting_v13
feat: Enable discount accounting
2021-08-10 11:48:14 +05:30
Subin Tom
2ab62a4484 fix: Missing method reset_issue_metrics added back to Issue doctype (#26574) 2021-08-10 11:43:59 +05:30
Noah Jacob
10ce2f5d6e refactor: added naming series for pricing rule 2021-08-10 11:42:59 +05:30
noahjacob
dd86642037 refactor: removed py2 code 2021-08-10 11:41:29 +05:30
noahjacob
b214e624bb style: fixed formatting 2021-08-10 11:41:29 +05:30
noahjacob
74bcb987f3 style: fixed formatting 2021-08-10 11:41:29 +05:30
noahjacob
4fb1b6b80c fix: Sider 2021-08-10 11:41:29 +05:30
noahjacob
a4cea1e56d refactor: variable names 2021-08-10 11:41:29 +05:30
noahjacob
3a663ac77f test: changed test item name 2021-08-10 11:41:29 +05:30
noahjacob
c95d96e7ae refactor: changed variable names 2021-08-10 11:41:29 +05:30
noahjacob
a9ef56a107 test: added test case for creating and updating 2021-08-10 11:41:29 +05:30
noahjacob
415519af15 feat: added multi-select fields to create multiple pricing rules. 2021-08-10 11:41:29 +05:30
rohitwaghchaure
c5e7673277 Merge pull request #26814 from noahjacob/mr_allowance_feat_v13
feat: over transfer allowance for material transfers (bp #26264)
2021-08-10 11:32:43 +05:30
Deepesh Garg
797170e913 fix: Linting issues 2021-08-10 11:02:21 +05:30
Deepesh Garg
428ccebad9 test: Update test cases for discount accounting 2021-08-10 10:43:01 +05:30
Deepesh Garg
b73bb3e501 fix: Add discount account handling in Purchase Invoice 2021-08-10 10:42:47 +05:30
Deepesh Garg
9b561ea839 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into discount_accounting_v13 2021-08-10 10:38:14 +05:30
Deepesh Garg
cd980f5e6b Merge pull request #26723 from GangaManoj/backport-po-payment-terms
feat: Fetch Payment Terms from linked Sales/Purchase Order
2021-08-10 10:34:39 +05:30
Deepesh Garg
f2c4699c9b Merge pull request #26867 from fproldan/fix_price_list_subscription_hotfix
fix: depends_on in price list field in Subscription Plan
2021-08-09 20:35:28 +05:30
Francisco Roldan
0a90302170 fix: depends_on in price list field 2021-08-09 11:41:56 -03:00
Frappe PR Bot
18bd182f61 patch: delete all orphaned tables docs (#26863) 2021-08-09 18:34:51 +05:30
Frappe PR Bot
0ff9ef673c fix: add parameter for db insert while adding item tax (#26855) (#26858)
(cherry picked from commit b3bbebd27c)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-08-09 17:58:18 +05:30
Ankush
9f5111809d test: fix flaky purchase receipt test (#26859) (#26860)
# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
2021-08-09 15:35:26 +05:30
Frappe PR Bot
ea83e2b45f fix: validate python expressions (#26835) (#26856)
(cherry picked from commit 07337d5c78)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-09 14:48:59 +05:30
Saqib
e7a77d9cb1 Merge pull request #26415 from GangaManoj/backport-asset-repair-refactor
refactor: Asset Repair
2021-08-09 12:46:05 +05:30
Marica
a8166c06c7 fix: Faulty Gl Entry for Asset LCVs (#26803)
* fix: Faulty Gl Entry for Asset LCVs

- Both Gl entries were crediting in their respective accounts
- Asset Account must be debited into

* fix: Use keyword arguments instead of positional for better readability

* chore: Test for LCV for draft asset created via Purchase Receipt
2021-08-09 12:38:12 +05:30
Frappe PR Bot
210441d9b5 fix: price list with 0 value are ignored (bp #26655)
* fix: price list with 0 value are ignored

Steps to reproduce:
1. Create 2 item price for two different supplier. One of them should be
   zero.
2. Create PO
3. Add supplier with non-zero price and add item.
4. change supplier. Price won't change. If price was non-zero it
   would've changed.

Root cause: falsiness check instead of null value check is used for
checking if price list value exists. 0 is evaluated as false.

* refactor: make get_price_list_rate function pure

(cherry picked from commit 16d4de5130)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-09 11:34:33 +05:30
Frappe PR Bot
3dfbf19e8f fix: allow alternative items when using job card (bp #26724)
(cherry picked from commit 7e0c57fa3f)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-09 11:33:55 +05:30
Frappe PR Bot
bba9aac9c0 feat: add french address template (bp #26316)
* add french address template

Co-authored-by: HENRY Florian <florian.henry@open-concept.pro>

(cherry picked from commit 07e65ab589)
2021-08-09 10:58:39 +05:30
Marica
e9c293d621 Merge pull request #25845 from noahjacob/item_so_variant_fix
fix: production plan not fetching sales order of a variant
2021-08-09 10:47:54 +05:30
Deepesh Garg
5ace2767af test: Fix test cases for payment terms fetch 2021-08-08 19:17:38 +05:30
Deepesh Garg
25d131a39f test: Improve test case for not coping payment terms 2021-08-07 17:39:40 +05:30
Deepesh Garg
a27ef14db6 fix: Override template only if setting is enabled 2021-08-07 00:12:57 +05:30
Deepesh Garg
a59a761f99 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into backport-po-payment-terms 2021-08-06 23:55:01 +05:30
Deepesh Garg
0bba425fe3 fix: Ignore default payment term templates when coping payment terms from orders 2021-08-06 23:53:16 +05:30
Frappe PR Bot
aec7846407 test: fix pricelist tests (#26839) (#26840)
problem: exchange rate API is returning exchange rates for "_Test currency".
These tests were relying on failure of that function.

(cherry picked from commit 27a29eb6bc)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-06 21:55:01 +05:30
Frappe PR Bot
9ea24db20a test: use item that allows fractional UOM in test (#26837) (#26838)
(cherry picked from commit 614336fe1d)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-06 21:14:40 +05:30
GangaManoj
fcbd79b7d3 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into backport-asset-repair-refactor 2021-08-06 18:12:24 +05:30
Frappe PR Bot
c8e6c07032 fix(e-invoicing): cannot generate IRNs for standalone credit notes (#26824) (#26833) 2021-08-06 12:33:18 +05:30
Noah Jacob
cb44aed78b test: get sales order with variant 2021-08-06 11:16:25 +05:30
Deepesh Garg
ffd7642de2 Merge pull request #26832 from deepeshgarg007/budget_test_case
test: Failing budget test due to project naming
2021-08-06 11:14:47 +05:30
Frappe PR Bot
2e352834a2 fix: fetching of item tax from hsn code (#26736) (#26792)
* fix: fetching of item tax from hsn code

(cherry picked from commit 3a50490c04)

Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-08-06 10:59:29 +05:30
Deepesh Garg
6871c07685 test: Failing budget test due to project naming 2021-08-06 10:53:38 +05:30
Frappe PR Bot
b13e46071a fix: Let all System Managers be able to delete Company transactions (#26815) (#26819)
(cherry picked from commit 884d8cf065)

Co-authored-by: Ganga Manoj <ganga.manoj98@gmail.com>
2021-08-06 10:39:58 +05:30
Nabin Hait
894ed3a9a5 Merge pull request #26765 from frappe/revert-24206-additional_salary_tax_enhancements
Revert "fix: Tax calculation for Recurring additional salary"
2021-08-06 10:22:31 +05:30
GangaManoj
232c728636 Revert "fix: Only fetch default Payment Terms Template if present"
This reverts commit fb80ca9e06.
2021-08-05 23:04:58 +05:30
GangaManoj
fb80ca9e06 fix: Only fetch default Payment Terms Template if present 2021-08-05 22:04:11 +05:30
GangaManoj
5c21eea13d fix: Fetch discount details from Payment Terms only if Discount Type = Percentage 2021-08-05 21:50:09 +05:30
GangaManoj
e4a07d8ff3 fix: Stop fetching amount while fetching Payment Terms 2021-08-05 21:42:09 +05:30
Frappe PR Bot
6e07ec2617 fix: Do not fetch fully return issued purchase receipts (#26809) (#26825)
(cherry picked from commit 1d90f7684e)

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-08-05 20:13:28 +05:30
Noah Jacob
041ac339b1 style: improved formatting of sql query 2021-08-05 16:37:22 +05:30
Noah Jacob
b10465eebe refactor: created function to get bom_item for query 2021-08-05 16:37:22 +05:30
noahjacob
9b0b2daf4a refactor: updated sql query for item variants 2021-08-05 16:37:22 +05:30
noahjacob
cf4078756d fix: fixed fetching sales order of item variant in production plan 2021-08-05 16:37:21 +05:30
Frappe PR Bot
5b5a365aaf fix: POS payment modes displayed wrong total (#26808) 2021-08-05 11:15:16 +05:30
GangaManoj
4a6ef9ab0f fix: Compare Payment Schedules 2021-08-05 00:52:55 +05:30
GangaManoj
0b11420147 fix: Disable automcatically_fetch_payment_terms after running its associated tests 2021-08-05 00:35:45 +05:30
GangaManoj
23c104555b fix: Remove irrelevant code 2021-08-05 00:28:42 +05:30
Frappe PR Bot
bf8d0c256d fix: typo in error message (#26816) (#26817)
(cherry picked from commit 005291e6dd)

Co-authored-by: François de Ryckel <f.deryckel@gmail.com>
2021-08-04 22:01:17 +05:30
Noah Jacob
673bc58193 test: test case for over transfer of materials 2021-08-04 18:48:24 +05:30
Noah Jacob
8fced95f8c feat: over transfer allowance for material transfers 2021-08-04 18:48:24 +05:30
GangaManoj
8328f45230 fix: Rename test to reflect changes in code 2021-08-04 17:33:35 +05:30
Frappe PR Bot
13192e1db1 fix: trigger lost reason dialog when status is changed to lost (#26811) (#26812)
(cherry picked from commit e5d8ba65ca)

Co-authored-by: Mohammed Yusuf Shaikh <49878143+mohammedyusufshaikh@users.noreply.github.com>
2021-08-04 17:07:22 +05:30
Anupam Kumar
df477dcae6 fix: bank remittance report issue (#26398) (#26766) 2021-08-04 14:02:43 +05:30
Dany Robert
9f94c19752 fix: ignore permission to update call log (#26797)
Backport of #26112
#no-docs
2021-08-04 10:01:44 +05:30
Frappe PR Bot
1b9a5c851d fix: incorrect amount in work order required items table. (#26585) (#26623)
* fix: amount in work order not equal to rate * qty

* fix: patch for amount in work order required items

(cherry picked from commit cd12d95a24)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-03 20:06:36 +05:30
Frappe PR Bot
85815f989c fix: Reset weight_per_unit on replacing Item (#26619) (#26791)
* fix: Assign Item's default weight_per_unit as its weight_per_unit in get_item_details

* fix: Set weight_uom in get_item_details as Item's default weight_uom

(cherry picked from commit 471f48f64d)

Co-authored-by: Ganga Manoj <ganga.manoj98@gmail.com>
2021-08-03 20:06:07 +05:30
Frappe PR Bot
5a442f1bce fix: change format string to percent string interpolation (#26774) (#26778)
(cherry picked from commit 7fe588e236)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-08-03 13:29:10 +05:30
Frappe PR Bot
373ed1f65c fix: remove limit from stock balance report (#26773) (#26779)
(cherry picked from commit b3740e9afc)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-03 13:28:50 +05:30
GangaManoj
f99696b75d fix: Condition for fetching Payment Terms from Sales/Purchase Orders 2021-08-02 23:15:44 +05:30
Deepesh Garg
db40d88fc2 Merge pull request #26780 from nemesis189/added-dispatch-address-to-sales-v13-new
feat: Added dispatch address fields in Sales Ord, Sales Inv, Delivery Note for Eway Bill
2021-08-02 21:11:50 +05:30
Subin Tom
6ba11a382a test: Updated test case for Eway bill 2021-08-02 20:36:46 +05:30
Subin Tom
8800aaaee7 feat: Added fields for dispatch address in Sales Order, Sales Invoice, Delivery Note for Eway Bill 2021-08-02 20:36:37 +05:30
Ankush
e43bdf76a5 chore: warning for shopify integration deprecation (#26701)
* chore: warning for shopify integration deprecation

* fix: warn deprecation during patch for sysadmins
2021-08-02 18:57:48 +05:30
Frappe PR Bot
a9474a9fbd fix: POS Invoice consolidated Sales Invoice field set to no copy (#26768) 2021-08-02 12:25:27 +05:30
Subin Tom
4597f151f5 fix: POS Item Cart non-stop scroll issue (#26693) 2021-08-02 11:38:31 +05:30
Subin Tom
a75c7c48d8 fix: missing QR Code in auto email attachment (#26599) 2021-08-02 11:34:28 +05:30
Nabin Hait
74bb55bfd2 Revert "fix: Tax calculation for Recurring additional salary (#24206)"
This reverts commit adfdc71844.
2021-08-01 20:03:38 +05:30
Frappe PR Bot
b5c7fce689 fix: student category mapping from the program enrollment tool (#26716) (#26739)
Co-authored-by: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
(cherry picked from commit 1a2332a81c)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-07-30 18:54:35 +05:30
Saqib
2d6f2fea5b fix: gl entries for exchange gain loss (#26728) 2021-07-30 10:55:53 +05:30
rohitwaghchaure
bd33bdf210 Merge pull request #26717 from deepeshgarg007/pricing_rule_item_group
fix: Parent condition in pricing rules
2021-07-29 19:51:53 +05:30
rohitwaghchaure
b7bbefee15 Merge pull request #26722 from rohitwaghchaure/skip-cancelled-entries-in-report
fix: remove cancelled entries from Stock and Account Value comparison report
2021-07-29 19:49:42 +05:30
Ankush
c7df759324 fix: empty "against account" in Purchase Receipt GLE bp #26712 (#26718)
* fix: correct field for GLE against account in PR

* fix: remove incorrect field check from reposting
2021-07-29 19:49:12 +05:30
GangaManoj
01ab63189a fix: Check if Purchase Order has Payment Terms Template 2021-07-29 19:28:14 +05:30
GangaManoj
6343950d82 fix: Sider issues 2021-07-29 19:27:54 +05:30
GangaManoj
57df4a3aa1 fix: Rename tests 2021-07-29 19:27:54 +05:30
GangaManoj
0413a5aafd fix: Add test to check if payment terms are fetched when creating a Purchase Invoice 2021-07-29 19:27:52 +05:30
GangaManoj
e94604f517 fix: Add test to check if payment terms are fetched when creating a Purchase Invoice 2021-07-29 19:26:39 +05:30
GangaManoj
293c5e10c3 fix: Add test to check if payment terms are fetched when creating a Sales Invoice 2021-07-29 19:26:39 +05:30
GangaManoj
59d1cc02c5 fix: Add test to check if payment terms are fetched when creating a Sales Invoice 2021-07-29 19:26:39 +05:30
GangaManoj
def7cc6cb3 fix: Modify set_payment_schedule() to include fetch_payment_terms_from_order() 2021-07-29 19:26:39 +05:30
GangaManoj
6333c3bee5 fix: Remove unused imports 2021-07-29 19:26:00 +05:30
GangaManoj
b389c9e375 fix: Fetch Payment Terms from Sales/Purchase Orders 2021-07-29 19:25:29 +05:30
GangaManoj
1011c1b01a fix: Clear Payment Schedule if PI has default Payment Schedule, but linked PO doensn't 2021-07-29 19:24:29 +05:30
Deepesh Garg
19a6d80927 fix: Parent condition in pricing rules 2021-07-29 18:47:16 +05:30
Rohit Waghchaure
379ce70126 fix: remove cancelled entries from Stock and Account Value comparison report 2021-07-29 18:06:17 +05:30
Deepesh Garg
e014d7a00e Merge pull request #26710 from deepeshgarg007/tds_194q_calculations
fix: TDS calculation for first threshold breach for TDS category 194Q
2021-07-29 15:55:16 +05:30
Saqib
e39bbc85e1 fix: cannot cancel payment entry if linked with invoices (#26703) 2021-07-29 15:46:25 +05:30
Nabin Hait
237150d1f4 Merge pull request #26630 from rohitwaghchaure/show-progress-completion-status-in-repost-item-valuation
fix: added progress bar in repost item valuation to check the status
2021-07-29 15:37:35 +05:30
Deepesh Garg
4c681592bf fix: TDS calculation for first threshold breach for TDS category 194Q 2021-07-29 15:26:19 +05:30
Frappe PR Bot
6a71955b99 chore: change location of backport action (#26705) (#26707)
(cherry picked from commit e906acdc49)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-07-29 14:28:13 +05:30
Jannat Patel
285463b031 Merge pull request #23129 from anupamvs/email-digest
fix: multiselect recipients in Email Digest
2021-07-29 12:36:49 +05:30
Ankush
8859574aab feat: don't recompute taxes (#26694) 2021-07-29 11:09:22 +05:30
Anupam
e5fea372af fix: frappe linter 2021-07-29 11:05:38 +05:30
Anupam
b1350af1f6 fix: setup wizard 2021-07-28 23:54:46 +05:30
Anupam Kumar
89f2138fbc Merge branch 'version-13-hotfix' into email-digest 2021-07-28 18:24:29 +05:30
Frappe PR Bot
1b6dd84c0a fix(bom): remove manual permission checking (#26689) (#26690)
get_list does the permission checking.

(cherry picked from commit d95f16ac8f)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-07-28 18:11:11 +05:30
Deepesh Garg
4c0dfdb398 Merge pull request #26687 from deepeshgarg007/fieldtype_fix
fix: Change fieldtype from data to check
2021-07-28 15:59:08 +05:30
Deepesh Garg
fa8e6ac7cd fix: Patch 2021-07-28 15:30:05 +05:30
Afshan
90c5cb0a31 fix: documentation link for E Invoicing (#26685) 2021-07-28 13:42:33 +05:30
Deepesh Garg
9350249941 fix: Chnage fieldtype from data to check 2021-07-28 12:57:59 +05:30
Deepesh Garg
7365e9704f Merge pull request #26683 from deepeshgarg007/tds_194q_fix
fix(minor): Consider grand total for threshold check
2021-07-28 11:56:29 +05:30
Deepesh Garg
1c9e516092 fix: GL Entries for discount amount with item qty greater than 1 2021-07-28 11:38:44 +05:30
Deepesh Garg
64af124f88 fix(minor): Consider grand total for threshold check 2021-07-28 10:43:02 +05:30
Raffael Meyer
ac2e139d5b fix: force reload of Opportunity in patch (#26668) 2021-07-28 00:14:59 +05:30
Rohit Waghchaure
56b81565fa fix: added progress bar in repost item valuation 2021-07-27 22:11:30 +05:30
rohitwaghchaure
965b1fe4a0 Merge pull request #26675 from rohitwaghchaure/fixed-dict-object-has-no-attr
fix: not able to add employee in the job card
2021-07-27 18:47:45 +05:30
Rohit Waghchaure
af58ac9e10 fix: not able to add employee in the job card 2021-07-27 18:43:20 +05:30
Nabin Hait
11a1610781 Merge pull request #26661 from deepeshgarg007/tds_enhancements
feat: Enhancements in Tax Withholding Category
2021-07-27 18:26:00 +05:30
Frappe PR Bot
b122a1eaa0 fix: reload manufacturing setting before patch (#26641) (#26670)
(cherry picked from commit c8d7a8c781)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-07-27 16:59:06 +05:30
Deepesh Garg
f28595cad0 Merge pull request #26650 from deepeshgarg007/exchange_rate_reval_fixes_v13
fix: Exchange rate revaluation posting date and precision fixes
2021-07-27 16:41:23 +05:30
Deepesh Garg
6e6823c3aa feat: Enhancements in TDS 2021-07-27 10:59:25 +05:30
Jannat Patel
5448aa25e7 chore: code owners updated (#26659) 2021-07-27 10:18:53 +05:30
Deepesh Garg
3fae0db8d9 Merge pull request #26550 from nemesis189/ignore-mandatory-in-payment-reconcilitation-v13
fix: Ignore mandatory fields while creating payment reconciliation Journal Entry
2021-07-27 10:15:39 +05:30
Deepesh Garg
2922fb52cc Merge pull request #26616 from deepeshgarg007/gst_sales_register_fix
fix(India): Default value for export type
2021-07-27 10:12:02 +05:30
Jannat Patel
6c48a2ed79 fix: Removed set_status after cancel from Expense Claim and Employee Advance (#25901)
* fix: removed set_status after cancel from hr doctypes

* fix: semgrep on_submit issue

* fix: sider

* fix: spaces

* fix: update flag for db_set
2021-07-27 09:41:55 +05:30
Jannat Patel
aaea5edbdb fix: Salary component account filter (#26605)
* fix: salary component account filter

* fix: cleanup
2021-07-27 09:39:33 +05:30
Frappe PR Bot
cfd73ed554 ci: auto backport squashed commits based on labels (#26622) (#26640)
(cherry picked from commit 057a0a9842)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-07-26 19:42:19 +05:30
Deepesh Garg
23776600f3 Merge pull request #26544 from deepeshgarg007/gstr_3b_missing_cess
fix: Add missing cess amount in GSTR-3B report
2021-07-26 19:20:42 +05:30
Deepesh Garg
6330318381 Merge pull request #26575 from deepeshgarg007/gst_reports_timeout
fix: GST Reports timeout issue
2021-07-26 19:19:16 +05:30
Deepesh Garg
dc2cd35b93 fix: Convert null values to empty string on grouping 2021-07-26 19:07:02 +05:30
Deepesh Garg
5749e52bf6 fix: Ignore GL Entry on cancel 2021-07-26 19:06:51 +05:30
Deepesh Garg
fb72df7dce fix: Exchange rate revaluation posting date and precision fixes 2021-07-26 19:06:40 +05:30
Deepesh Garg
8d52a22709 fix: Additional discount calculations in Invoices (#26553)
* fix: Additional discount calculations in Invoices

* revert: Client side handling for Dynamic GST Rates

* fix: Add update item tax template method back

* fix: Revert refresh field

* fix: add company change trigger
2021-07-26 19:00:57 +05:30
Deepesh Garg
d066eab6cd fix: Test case for GSTR-3b report 2021-07-26 18:38:50 +05:30
Deepesh Garg
0011585415 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into gst_sales_register_fix 2021-07-26 17:21:13 +05:30
Subin Tom
06fb0b93b5 fix: Supplier invoice importer fix v13 (#26633)
* fix: Supplier Invoice Importer fix
Co-authored-by: Subin Tom <subin-home@Subins-MacBook-Air.local>
2021-07-26 16:46:47 +05:30
Frappe PR Bot
4209b3bda9 fix: included company in Link Document Type filters for contact (#26576) (#26634)
(cherry picked from commit cbddedab7b)

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-07-26 13:00:32 +05:30
Rucha Mahabal
c676eaae57 fix: test 2021-07-25 23:11:18 +05:30
Rucha Mahabal
6bca87ddb9 fix: remove unnecessary imports 2021-07-25 21:34:51 +05:30
Rucha Mahabal
475d856d66 fix(style): longer titles overflowing 2021-07-25 20:39:51 +05:30
Rucha Mahabal
37198159aa feat: Export chart option in desktop view 2021-07-25 20:28:01 +05:30
Rucha Mahabal
57cb3ac023 feat: add html2canvas for easily exporting html to images using canvas 2021-07-25 20:23:20 +05:30
Rucha Mahabal
017ed3f5c1 fix: employee status server-side validation (#26615) 2021-07-24 00:08:02 +05:30
rohitwaghchaure
9052a3b1a8 Merge pull request #26614 from rohitwaghchaure/fixed-serial-no-not-link-to-batch-error
fix: serial no and batch validation
2021-07-23 23:38:02 +05:30
rohitwaghchaure
9ef157b23b fix: wrong operation time in Work Order (#26613)
* fix: wrong operation time in Work Order

Top level item time operation was not considering the BOM.quantity

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-07-23 20:44:34 +05:30
Deepesh Garg
328444b530 fix(India): Default value for export type 2021-07-23 20:28:02 +05:30
Rohit Waghchaure
45d506c489 fix: serial no and batch validation 2021-07-23 16:40:45 +05:30
rohitwaghchaure
56c67743ab fix: incorrect bom name (#26600) 2021-07-22 16:10:06 +05:30
Ankush
5b32fa5ccd fix: SQL error on fetching RM in production plan (bp #26592)
* fix: SQL error on fetching RM in production plan

* refactor: avoid passing by reference and mutations
2021-07-22 14:00:01 +05:30
Deepesh Garg
2ff0d3e0eb fix: Test Cases 2021-07-22 10:43:16 +05:30
rohitwaghchaure
49c5cd66f3 Merge pull request #26586 from rohitwaghchaure/removed-remarks-field-from-ar-ap-report
fix: removed Remarks column from AR/AP report
2021-07-22 10:27:15 +05:30
Rucha Mahabal
1176761757 feat: Expand All nodes option in Desktop view 2021-07-21 23:19:47 +05:30
Deepesh Garg
c765073c2a fix: Tests 2021-07-21 22:28:32 +05:30
Ankush Menat
6928fc17c6 chore: remove warning rules
semgrep-action doesn't consider severity, hence ignoring these rules for now.
2021-07-21 19:56:15 +05:30
Rohit Waghchaure
f3158ea448 fix: removed Remarks column from AR/AP report 2021-07-21 19:47:41 +05:30
rohitwaghchaure
ac6bfeaa8d Merge pull request #26558 from rohitwaghchaure/fixed-incorrect-gross-profit-report
fix: incorrect valuation rate calculation in gross profit report
2021-07-21 19:35:55 +05:30
Deepesh Garg
5a06019440 fix: GL For taxes if discount applied on Grand Total 2021-07-21 15:25:40 +05:30
Deepesh Garg
fc09d845c5 fix: Syntax Error 2021-07-21 15:25:09 +05:30
Deepesh Garg
55325ef3a3 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into discount_accounting_v13 2021-07-21 14:27:05 +05:30
GangaManoj
4fa409e019 fix: Add mandatory_depends_on property for Discount Account 2021-07-21 14:26:52 +05:30
GangaManoj
45327e04db fix: Tests 2021-07-21 14:26:52 +05:30
GangaManoj
1f6c05f013 fix: Make discount_account mandatory if discount accounting is enabled 2021-07-21 14:26:52 +05:30
GangaManoj
566e8f8499 fix: Create GL Entries for Additional Discount Account 2021-07-21 14:26:51 +05:30
Ganga Manoj
ed6ebdf5ed fix: Filter for additional_discount_account
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-07-21 14:24:21 +05:30
Ganga Manoj
821b75f1b1 fix: Filter for additional_discount_account
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-07-21 14:24:21 +05:30
Ganga Manoj
f421dc7ca7 fix: GL Entry creation
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-07-21 14:24:21 +05:30
Ganga Manoj
e7e9bda123 fix: Use the item's project instead of the invoice's
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-07-21 14:24:21 +05:30
Ganga Manoj
b4a8bc8e4c fix: Use the item's cost centre instead of the Invoice's
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-07-21 14:24:21 +05:30
GangaManoj
251f229601 fix: Add test for additional discount applied on taxes 2021-07-21 14:23:53 +05:30
GangaManoj
99cb89f449 fix: Switch debit and credit for ledger entries for discount applied on taxes for Purchase Invoice 2021-07-21 14:23:53 +05:30
GangaManoj
99652876d0 fix: Add test for additional discount applied on taxes 2021-07-21 14:23:53 +05:30
GangaManoj
d62af77ca8 fix: Remove unnecessary condition 2021-07-21 14:23:52 +05:30
GangaManoj
4da7c5882b fix: Only display Additional Discount Account if Enable Discount Accounting is checked 2021-07-21 14:23:52 +05:30
GangaManoj
9dd2a9e897 fix: Create ledger entries for discount applied on taxes in make_tax_gl_entries 2021-07-21 14:23:52 +05:30
GangaManoj
ff25683378 fix: Filter options for Additional Discount Account 2021-07-21 14:23:52 +05:30
GangaManoj
03f2706971 fix: Add Additional Discount Account field 2021-07-21 14:23:52 +05:30
GangaManoj
d0d9e83ad2 fix: Check all expected GL Entries 2021-07-21 14:23:52 +05:30
GangaManoj
d6f409addc fix: Sider issues 2021-07-21 14:23:52 +05:30
GangaManoj
38327fc177 fix: Make additional GL Entries for discount applied on taxes 2021-07-21 14:23:52 +05:30
GangaManoj
b64787ee9c fix: Only display Additional Discount Account if Enable Discount Accounting is checked 2021-07-21 14:23:52 +05:30
GangaManoj
c1d65cfa8d fix: Filter options for Additional Discount Account 2021-07-21 14:23:52 +05:30
GangaManoj
9e788cfdcd fix: Add Additional Discount Account field 2021-07-21 14:23:52 +05:30
GangaManoj
38e87fce09 fix: Add tests for discount accounting 2021-07-21 14:23:51 +05:30
GangaManoj
fd2852e87e fix: Create common function for discount accounting 2021-07-21 14:23:15 +05:30
GangaManoj
e06eb8e6a9 fix: Filter options for Discount Account 2021-07-21 14:22:26 +05:30
GangaManoj
377775ad8e fix: Copy Discount Account from first row 2021-07-21 14:22:25 +05:30
GangaManoj
e2c83c3baf fix: Display Discount Account only if Enable Discount Accounting is checked 2021-07-21 14:21:32 +05:30
GangaManoj
bde5c619db fix: Add Discount Account field 2021-07-21 14:21:31 +05:30
GangaManoj
ee025b501f fix: Filter options for Default Discount Account 2021-07-21 14:21:16 +05:30
GangaManoj
546c8d125c fix: Move Default Discount Account field to Item Defaults 2021-07-21 14:21:16 +05:30
GangaManoj
613d08faad fix: Copy discount account from first row to all Items 2021-07-21 14:21:15 +05:30
GangaManoj
cfb94175a2 fix: Filter Discount Account list 2021-07-21 14:20:32 +05:30
GangaManoj
d24b5f707a fix: Add description for Enable Discount Accounting checkbox 2021-07-21 14:20:32 +05:30
GangaManoj
f48fa2e7f3 feat: Toggle display for discount accounting fields according to enable_discount_accounting 2021-07-21 14:20:06 +05:30
GangaManoj
cdfefa261e feat: Assign Item's Default Discount Account if present 2021-07-21 14:20:06 +05:30
GangaManoj
acb9e207ec feat: Add Default Discount Account field 2021-07-21 14:20:06 +05:30
GangaManoj
c4e5429560 feat: Filter list for Discount Account field in Items table 2021-07-21 14:20:06 +05:30
GangaManoj
f6a9374356 feat: Create GL Entries for discount accounting 2021-07-21 14:20:06 +05:30
GangaManoj
a6690a8a3d feat(Sales Invoice): Add 'Discount Account' field in Items table 2021-07-21 14:20:06 +05:30
GangaManoj
e1dc6980d0 feat(Accounts Settings): Add 'Enable Discount Accounting' checkbox 2021-07-21 14:20:06 +05:30
Deepesh Garg
8a64a84d1a fix: GST Reports timeout issue 2021-07-21 13:25:53 +05:30
rohitwaghchaure
f60cba28ab Merge pull request #26506 from 18alantom/bp-fix-ig-portal-field-filter
fix: check if field_filters is None
2021-07-21 11:28:06 +05:30
Rucha Mahabal
57514f7b1d feat(Non Profit): API Endpoint to update halted Razorpay subscriptions (#26427) (#26564)
* feat: Update Subscription Activated field to Subscription Status to accomodate Halted status

* feat: API Endpoint to halt Razorpay subscription

* fix: sider

* fix: validation message

* test: halted razorpay subscription
2021-07-21 00:46:34 +05:30
Ganga Manoj
41705acbd9 fix: delete child docs when parent doc is deleted (#26518)
* fix: Make code more readable

* fix: Delete child table info when parent doc is deleted

* fix: Sider issues

* fix: Remove trailing whitespace
2021-07-20 20:48:57 +05:30
Subin Tom
2d225e621f fix: Price list rate not fetched for return sales invoice fixed (#26560)
Co-authored-by: Subin Tom <subin-home@Subins-MacBook-Air.local>
2021-07-20 20:41:04 +05:30
Rohit Waghchaure
c14aa45720 fix: incorrect valuation rate calculation in gross profit report 2021-07-20 18:19:15 +05:30
Rucha Mahabal
0222ee0358 fix: sider 2021-07-20 12:19:44 +05:30
Suraj Shetty
cbe5718db9 Merge pull request #26555 from surajshetty3416/fix-customer-quick-entry-version-13-hotfix 2021-07-20 11:13:21 +05:30
Rucha Mahabal
41dd0c5a8a fix: sider 2021-07-20 10:55:05 +05:30
Suraj Shetty
85c8daae9c fix: Pass doc and other parameters to properly prefill information - while creating customer from form dashboard 2021-07-20 10:24:14 +05:30
Rucha Mahabal
eb65ce662a fix(test): increase timeout for record creation 2021-07-20 10:23:52 +05:30
Rucha Mahabal
7176c0847e fix: tests 2021-07-19 23:34:02 +05:30
Rucha Mahabal
89c5bb6066 fix: tests 2021-07-19 22:19:28 +05:30
Ankush
92273cade0 fix(ux): item description should fall back to name (#26339) (#26552)
Don't set item description = item code from front end. This is already
being set to item_name in before_insert and item_name is better
fallback than item code for description.

Also fixed wrong condition for erasing description while duplicating
item.
2021-07-19 20:44:05 +05:30
Subin Tom
ff9d631f15 fix:Ignore mandatory fields while creating payment reconciliation Journal Entry 2021-07-19 20:28:34 +05:30
Rucha Mahabal
e327148edf fix: tests 2021-07-19 17:34:15 +05:30
Rucha Mahabal
6e46be5058 fix(tests): apply filters correctly 2021-07-19 17:03:17 +05:30
Rucha Mahabal
7270ab5c20 fix(tests): clear filter before typing 2021-07-19 16:26:17 +05:30
Rucha Mahabal
9d89b2afcf fix: UI tests 2021-07-19 15:47:31 +05:30
Deepesh Garg
cad1170782 fix: Add missing cess amount in GSTR-3B report 2021-07-19 14:36:54 +05:30
Deepesh Garg
ce79faa738 Merge pull request #26539 from dj12djdjs/fix-req-argument
fix: missing parameter 'country'
2021-07-18 17:48:22 +05:30
Devin Slauenwhite
d5ff636159 fix: missing parameter 'country' 2021-07-17 14:42:38 -04:00
Ankush
d8ed9dfcf4 chore: update CODEOWNERS (#26536) (#26537) 2021-07-17 12:49:56 +05:30
Nabin Hait
9ddf33715e Merge pull request #26513 from rohitwaghchaure/patch-to-fix-missing-fg-item
fix: added patch to fix missing FG item
2021-07-16 15:05:23 +05:30
Noah Jacob
3362c080b6 fix: validation check when no conversion_factor (#26527) 2021-07-16 15:00:08 +05:30
Rohit Waghchaure
13e9aa5956 fix: added patch to fix missing FG item 2021-07-16 14:34:24 +05:30
Ankush
627a8a8cfd chore: disable semgrep on push events (bp #26523) 2021-07-16 13:03:18 +05:30
Rucha Mahabal
2c3866a53e ci(cypress): use env variable for key
documentation ref: https://docs.cypress.io/guides/guides/command-line\#cypress-run
2021-07-16 10:32:38 +05:30
GangaManoj
56cdcebbf4 fix: Sider issues 2021-07-16 02:23:55 +05:30
Rucha Mahabal
8961a267f6 fix: sider 2021-07-15 19:32:15 +05:30
Ankush
b164070a4f ci: make semgrep ignore existing errors (bp #26516) 2021-07-15 19:31:59 +05:30
Rucha Mahabal
ee7eaf9c70 test: UI tests for org chart mobile
fix(mobile): detach node before emptying hierarchy

fix(mobile): sibling group not rendering for first level
2021-07-15 19:19:09 +05:30
Afshan
9b9b18c286 fix: improving ux for additional discount field (#26502) 2021-07-15 18:11:22 +05:30
Noah Jacob
26a9d38547 fix: WIP needs to be set before submit on skip_transfer (#26500) 2021-07-15 16:50:41 +05:30
Noah Jacob
d319e10883 fix: set default operation time to 0 (#26511) 2021-07-15 16:49:55 +05:30
rohitwaghchaure
4d444559ff Merge pull request #26508 from rohitwaghchaure/fixed-fg-items-not-added-for-batch-item
fix: FG item not fetched in manufacture entry
2021-07-15 15:32:05 +05:30
Rohit Waghchaure
74b97b5ec9 fix: FG item not fetched in manufacture entry 2021-07-15 14:52:21 +05:30
Deepesh Garg
1524e7f5ba Merge pull request #26412 from deepeshgarg007/payment_entry_taxes_v12
fix: Unallocated amount in Payment Entry after taxes
2021-07-15 12:38:23 +05:30
18alantom
12f7befa13 fix: check if field_filters is None 2021-07-15 12:09:33 +05:30
Rucha Mahabal
f004b404d1 test: UI tests for org chart desktop 2021-07-14 23:50:54 +05:30
Marica
4aebb64165 Merge pull request #26498 from marination/paging-btns-htofix
fix: Paging buttons not working on item group portal page
2021-07-14 21:21:20 +05:30
marination
219623279f fix: Paging buttons not working on item group portal page 2021-07-14 20:50:22 +05:30
Marica
a5f8accd63 Merge pull request #26492 from 18alantom/bp-fix-item-group-portal-issues
fix: item group portal issues (backport)
2021-07-14 18:12:46 +05:30
18alantom
e244560fb9 fix: set item group as a persistent filter 2021-07-14 17:40:10 +05:30
18alantom
7558e7f115 fix: show child item group items on portal 2021-07-14 17:40:04 +05:30
Noah Jacob
2c67894135 fix: validation check for batch for stock reconciliation type in stock entry(bp #26370 ) (#26487)
* fix(ux): added filter for valid batch nos.

* fix: not validating batch no if entry type stock reconciliation

* test: validate batch_no
2021-07-14 16:28:40 +05:30
Kenneth Sequeira
513375f264 fix: Nested/Multi-level BOM help link (#26409)
Updated the link for multi-level boms. Current link is broken.
2021-07-14 16:07:47 +05:30
Kenneth Sequeira
7a89033163 fix: update integration links in help.js (#26483) 2021-07-14 16:07:31 +05:30
Saqib
ac721ae147 fix: tds computation summary shows cancelled invoices (#26485) 2021-07-14 15:20:14 +05:30
Saqib
9c04079d04 fix: test fails due to improper gain loss account set (#26482) (#26484) 2021-07-14 14:45:11 +05:30
Afshan
9168bb369a fix: filter by accounts with group by accounts (#26439) 2021-07-14 13:57:14 +05:30
Saqib
cbf7e1b676 fix: pos item cart dom updates (#26460) 2021-07-14 11:40:47 +05:30
Anurag Mishra
adfdc71844 fix: Tax calculation for Recurring additional salary (#24206)
* fix: Tax calculation for Recurring additional salary

* fix: conflicts
2021-07-14 09:59:41 +05:30
rohitwaghchaure
96eb147bb6 Merge pull request #26457 from rohitwaghchaure/fixed-multi-currency-issue
fix: multi-currency issue
2021-07-13 23:01:30 +05:30
Deepesh Garg
75f66f78d7 Merge pull request #26420 from deepeshgarg007/new_company_error
fix: Errors on parallel requests creation of company for India
2021-07-13 20:29:56 +05:30
Deepesh Garg
fc20ff02d0 Merge pull request #26418 from deepeshgarg007/gstr_1_json_dpwnload_error
fix: Unable to download GSTR-1 json
2021-07-13 16:17:37 +05:30
Deepesh Garg
eef8e4a9d4 Merge pull request #26292 from deepeshgarg007/amended_doc_discount
fix: Incorrect discount amount on amended document
2021-07-13 15:34:24 +05:30
Rohit Waghchaure
0d190bb930 fix: multi-currency issue 2021-07-13 15:32:39 +05:30
Rucha Mahabal
40793f4a18 test: introduce cypress tests
Co-authored-by: Ankush <ankush@iwebnotes.com>
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2021-07-13 13:17:19 +05:30
Rucha Mahabal
fc4079587b Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into org-chart 2021-07-13 12:38:37 +05:30
rohitwaghchaure
84f23ac8d2 Merge pull request #26222 from 18alantom/teabox-cogs-by-item-group
feat: report to show cogs by item groups
2021-07-13 11:24:59 +05:30
Deepesh Garg
4a2e4748ac fix: Unallocated amount for inclusive charges 2021-07-13 11:22:55 +05:30
Deepesh Garg
30f771b26c Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into payment_entry_taxes_v12 2021-07-12 23:34:13 +05:30
Deepesh Garg
855e9030f2 fix: Deduct included taxes from unallocated amount 2021-07-12 22:11:57 +05:30
Saqib
7fb64d1645 fix: exchange gain loss not set for advances linked with invoices (#26436) 2021-07-12 18:33:16 +05:30
Deepesh Garg
1298956482 fix: Use update flag for company dependant fixtures 2021-07-12 18:29:52 +05:30
Nabin Hait
ca6e4bed9f Merge pull request #26431 from nabinhait/reposting-optimization
refactor: Optimized code for reposting item valuation
2021-07-12 15:42:24 +05:30
Saqib
b75b556bbb fix: move the rename abbreviation job to long queue (#26435) 2021-07-12 14:32:37 +05:30
Nabin Hait
45e6cffa4f refactor: Optimized code for reposting item valuation 2021-07-12 13:26:08 +05:30
Jannat Patel
38994bd494 fix: Added Company filters for Loan (#26294)
* fix: loan validations

* fix: added company filter while fetching loans

* fix: tests
2021-07-12 13:01:31 +05:30
Afshan
10473b1195 fix: dunning calculation of grand total when rate of interest is 0% (#26285) 2021-07-12 11:11:29 +05:30
Afshan
bf03671a33 fix(report): iterate on accounts only when accounts exist (#26391) 2021-07-12 11:10:28 +05:30
Afshan
f60c3f0655 fix: error popup for COA errors (#26358) 2021-07-12 11:07:30 +05:30
Saqib
432d8efa3d fix(pos): taxes amount in pos item cart (#26411) 2021-07-12 10:47:40 +05:30
Ankush
caacd0ad2c fix: stock levels disapperaing on refresh (bp #26305)
refresh_section removes all sections with `custom` class, added
different class to avoid this behaviour.

# Conflicts:
#	erpnext/stock/doctype/item/item.js
2021-07-12 10:20:19 +05:30
Marica
f7748e4109 Merge pull request #26133 from marination/qi-rejection
feat: Optionally allow rejected quality inspection on submission
2021-07-10 21:04:32 +05:30
Deepesh Garg
e282effaed fix: Error on creation of company for India 2021-07-10 20:23:52 +05:30
marination
c8a825c478 chore: Test case for QI Rejection in Stock Entry
- Use `get_single_value` instead of `get_doc` in validation
- Test Case to check impact of stock settings on SE with rejected qi
2021-07-10 18:26:36 +05:30
Deepesh Garg
77f2d2d01e fix: Unable to download GSTR-1 json 2021-07-10 10:06:38 +05:30
Saqib
2e507b47a8 fix(Asset Repair): cancellation 2021-07-09 22:39:34 +05:30
GangaManoj
073b50f7fd fix(Asset Repair): Rearrange fields 2021-07-09 22:38:58 +05:30
GangaManoj
fd7fb37697 fix(Asset Repair): Simplify code for Asset Repair creation in tests 2021-07-09 22:38:58 +05:30
GangaManoj
e328e3b48a fix(Asset Repair): Edit description for total_repair_cost 2021-07-09 22:38:57 +05:30
GangaManoj
c8caafa680 fix(Asset Repair): Move filters for cost_center, warehouse and project to setup 2021-07-09 22:38:57 +05:30
GangaManoj
267fed2d23 fix(Asset): Add comment 2021-07-09 22:38:57 +05:30
GangaManoj
597016bb34 fix(Asset): Remove extra tabs 2021-07-09 22:38:57 +05:30
GangaManoj
7c37e83535 fix(Asset): Remove to_date field 2021-07-09 22:38:57 +05:30
GangaManoj
cba0966ec5 fix(Asset Repair): Change controller hooks 2021-07-09 22:38:57 +05:30
GangaManoj
81bcae7433 fix(Asset): Remove redundant code 2021-07-09 22:38:57 +05:30
GangaManoj
f3ae1dd23b fix(Asset): Fix test 2021-07-09 22:38:57 +05:30
GangaManoj
18bbfdf343 fix(Asset Repair): Remove test that's no longer necessary 2021-07-09 22:38:56 +05:30
GangaManoj
39dba43b87 fix(Asset): Fix value_after_depreciation calculation 2021-07-09 22:38:56 +05:30
GangaManoj
3ba9fb32de fix(Asset Repair): Replace asset_value with value_after_depreciation in tests 2021-07-09 22:38:56 +05:30
GangaManoj
72ea64f6ac fix: Sider issues 2021-07-09 22:38:49 +05:30
GangaManoj
307fe43e08 fix: Remove changes made to Asset Maintenance 2021-07-09 22:38:02 +05:30
GangaManoj
55bca4cbc7 fix(Asset Repair): Revert Stock Entry on cancellation 2021-07-09 22:38:02 +05:30
GangaManoj
c34e6b1889 fix(Asset): Fix tests for Asset Repair 2021-07-09 22:38:02 +05:30
GangaManoj
ba9558527d fix(Asset Repair): Return Depreciation Schedule to original state on cancellation 2021-07-09 22:37:08 +05:30
GangaManoj
6c2f4ce6a5 fix(Asset Repair): Increase stock quantity and decrease asset value on cancellation 2021-07-09 22:37:08 +05:30
GangaManoj
ad78888c86 fix(Asset Repair): Compute total_value instantly 2021-07-09 22:37:08 +05:30
GangaManoj
e921878633 fix: Rename 'Stock Item' to 'Asset Repair Consumed Item' 2021-07-09 22:37:08 +05:30
GangaManoj
852881e33e fix(Asset Repair): Fix tests 2021-07-09 22:37:04 +05:30
GangaManoj
42fd7ffbc0 fix(Asset Repair): Set completion_date on changing repair_status to 'Completed' 2021-07-09 22:36:05 +05:30
GangaManoj
68e0c96c03 fix(Asset Repair): Prevent some fields from being copied on duplicating the doc 2021-07-09 22:36:05 +05:30
GangaManoj
399d17e40e fix(Asset Repair): Make Error Description non-mandatory 2021-07-09 22:36:05 +05:30
GangaManoj
e755c74a60 fix(Asset Repair): Add Stock Entry field 2021-07-09 22:36:04 +05:30
GangaManoj
4004bcd436 fix(Asset Repair): Move Total Repair Cost to the Stock Consumption Details section 2021-07-09 22:36:04 +05:30
GangaManoj
bd1796cbb6 fix: Replace edit_dates with flags.increase_in_asset_life 2021-07-09 22:36:04 +05:30
GangaManoj
ae8cb335b6 fix(Asset Repair): Fix depreciation_amount calculation 2021-07-09 22:36:04 +05:30
GangaManoj
be536040df fix: Add comments 2021-07-09 22:36:04 +05:30
GangaManoj
bd336c7d8e fix(Asset): Add function to clear old depreciation schedule 2021-07-09 22:36:04 +05:30
GangaManoj
54cbc8324a fix(Asset Repair): Create GL Entries for each item in Stock Items 2021-07-09 22:36:04 +05:30
GangaManoj
50826f16ee fix(Asset): Replace asset_value with value_after_depreciation in Finance Books 2021-07-09 22:36:04 +05:30
GangaManoj
d354a301cb fix(Asset Repair): Display value_after_depreciation in Finance Books 2021-07-09 22:36:04 +05:30
GangaManoj
9520efb941 fix(Asset Repair): Filter Warehouse by Company 2021-07-09 22:36:03 +05:30
GangaManoj
96de4fdf1f fix(Asset Repair): Fix GL Entry creation 2021-07-09 22:36:03 +05:30
GangaManoj
71eaf3dbd8 fix(Asset Repair): Fix Sider issues 2021-07-09 22:36:03 +05:30
GangaManoj
75fbda10ad fix(Asset Repair): Make Cost Center non-mandatory 2021-07-09 22:36:03 +05:30
GangaManoj
0aaf88cc0a fix(Asset Repair): Uncheck allow_on_submit for all fields 2021-07-09 22:36:03 +05:30
GangaManoj
9779aa11fb fix(Asset Repair): Use existing function from asset.py for fetching fixed_asset_account 2021-07-09 22:36:03 +05:30
GangaManoj
aff9709525 fix(Asset Repair): Add mandatory_depends_on condition for Purchase Invoice 2021-07-09 22:36:03 +05:30
GangaManoj
17fa121779 fix(Asset Repair): Filter Cost Center and Project by Company 2021-07-09 22:36:03 +05:30
GangaManoj
867fd02b2d fix(Asset Repair): Add Company field 2021-07-09 22:36:03 +05:30
GangaManoj
5ab0cabf91 fix(Asset Repair): Make Stock Items and Warehouse mandatory if stock_consumption is checked 2021-07-09 22:36:03 +05:30
GangaManoj
654074ad7a fix(Asset Repair): Add title to error messages 2021-07-09 22:36:03 +05:30
GangaManoj
fd272569aa fix(Asset Repair): Display fields according to the state of the doc 2021-07-09 22:36:02 +05:30
GangaManoj
4e620c3b32 fix: Set asset_name as title 2021-07-09 22:35:49 +05:30
GangaManoj
65b2f9234b fix(Asset Repair): Set company when creating Stock Entry 2021-07-09 22:15:58 +05:30
GangaManoj
2833903ce5 fix(Asset Repair): Add tests 2021-07-09 22:15:42 +05:30
GangaManoj
70de974496 fix(Asset): Add depreciation schedule details in create_asset() 2021-07-09 22:15:42 +05:30
GangaManoj
3f9f0ffdfe fix(Asset Repair): Add Company in GL Entries 2021-07-09 22:15:42 +05:30
GangaManoj
c6ed66ec5b fix(Asset Repair): Remove unnecessary condition 2021-07-09 22:15:42 +05:30
GangaManoj
794807ecc3 fix(Asset Repair): Only modify depreciation schedule if calculate_depreciation is checked 2021-07-09 22:15:42 +05:30
GangaManoj
97193a4632 fix: Sider issues 2021-07-09 22:15:10 +05:30
GangaManoj
4e284433d1 fix: Fix depreciation_amount calculation 2021-07-09 22:12:46 +05:30
GangaManoj
42c70fba3c fix: Modify depreciation schedule when increase_in_asset_life is not a multiple of frequency_of_depreciation) 2021-07-09 22:11:50 +05:30
GangaManoj
58bc967073 fix: Rename 'Fixed Asset Depreciation Settings' to 'Fixed Asset Deafults' 2021-07-09 22:10:35 +05:30
GangaManoj
9e26f2d797 fix: Organize buttons 2021-07-09 22:08:56 +05:30
Deepesh Garg
eae7c1891f fix: Remove unintentional changes 2021-07-09 20:08:29 +05:30
Deepesh Garg
c13ac4ab11 fix: Remove unintentional changes 2021-07-09 20:00:55 +05:30
Deepesh Garg
171ee51507 fix: Hide amount after tax fields 2021-07-09 18:52:39 +05:30
Deepesh Garg
38fa3a3f89 fix: Unallocated amount in Payment Entry after taxes 2021-07-09 18:04:24 +05:30
Saqib
13d7043451 fix: column 'outstanding_amount' cannot be null (#26404) 2021-07-09 15:33:14 +05:30
Saqib
fe4f58d0f6 fix(e-invoicing): allow export invoice even if no taxes applied (#26405) 2021-07-09 15:32:54 +05:30
Saqib
8e8434a78a fix: omit item discount amount for e-invoicing (#26353) (#26407) 2021-07-09 15:32:28 +05:30
Subin Tom
9ac63da457 fix: value fetching for custom field in POS (#26367) 2021-07-09 14:35:11 +05:30
Subin Tom
d53991857c fix: Fixed Budget Variance Graph color from all black to default (#26368) 2021-07-09 14:33:00 +05:30
Marica
eb0dea09bb Merge pull request #26333 from marination/lcv-validate-invoice
fix: Validate LCV for Invoices without Update Stock
2021-07-09 13:41:34 +05:30
Marica
01be96adb2 Merge branch 'version-13-hotfix' into qi-rejection 2021-07-09 13:30:21 +05:30
marination
bf462abb00 fix: Rename function and tweak logic
- Dont validate PI on `else`
2021-07-09 13:12:33 +05:30
Anurag Mishra
afafe406c8 Merge pull request #26388 from Anurag810/training_fix_v13
fix: Query for Training Event
2021-07-09 12:21:17 +05:30
Saqib
8f3c7ab402 fix: escape quotes while fetching customer emails (#26329) (#26376) 2021-07-09 10:35:55 +05:30
Rucha Mahabal
4582f28d0d fix: sider 2021-07-09 01:25:26 +05:30
Rucha Mahabal
24b31c0bf9 fix(mobile): collapsed nodes not expanding 2021-07-09 01:03:02 +05:30
Rucha Mahabal
e5a1bb7141 Merge pull request #26394 from ruchamahabal/fix-test-precision
fix: precision for expected values in payment entry test
2021-07-08 23:46:19 +05:30
Rucha Mahabal
3888488b36 fix: precision for expected values in payment entry test 2021-07-08 23:21:48 +05:30
Rucha Mahabal
06fc9e7847 fix: sibling group expansion not working for root nodes 2021-07-08 18:44:53 +05:30
Alan
257cbd3b92 fix: track changes on batch (#26382) 2021-07-08 18:44:30 +05:30
Anurag Mishra
a82e9e42e1 fix: query for training Event 2021-07-08 17:27:21 +05:30
Rucha Mahabal
09c24c7949 fix: exclude active node while fetching sibling group 2021-07-08 17:05:40 +05:30
Rucha Mahabal
05ffc0d3e0 feat: use icon for connections on mobile view 2021-07-08 16:55:42 +05:30
Jannat Patel
cf28950327 Merge pull request #26349 from Anurag810/salary-slip-fix--hotfix
fix: payroll-entry minor fix
2021-07-08 13:43:55 +05:30
Anurag Mishra
8f945a9852 fix: Removed un-used flag 2021-07-08 13:06:04 +05:30
Rucha Mahabal
48018b8d8c fix: do not sort by number of connections 2021-07-08 11:23:50 +05:30
Rucha Mahabal
df3bb9ea8c perf: Optimise Rendering
- optimise get_children function

- use promises instead of callbacks

- optimise selectors

- use const wherever possible

- use pure js instead of jquery for connectors for faster rendering
2021-07-08 09:53:31 +05:30
Mohammad Hasnain Mohsin Rajan
00f90c50c0 chore: add product listing link in settings (#26026)
* chore: add product listing link in settings

* chore: add icon in workspace card

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-07-07 18:21:12 +05:30
Rucha Mahabal
6eec251273 feat: handle multiple root / orphan nodes 2021-07-07 12:05:50 +05:30
Rucha Mahabal
6d5ee25bba fix: unnecessary variables 2021-07-07 09:43:28 +05:30
rohitwaghchaure
f130f8385e Merge pull request #26332 from rohitwaghchaure/fixed-bom-stock-report-not-working
fix: bom stock report not working
2021-07-07 00:22:03 +05:30
rohitwaghchaure
2bdc0e8993 Merge pull request #26350 from rohitwaghchaure/fixed-putaway-fixing-for-material-receipt
fix: stock entry with putaway rule not working
2021-07-07 00:15:26 +05:30
Rohit Waghchaure
0bd190b885 fix: stock entry with putaway rule not working 2021-07-07 00:14:51 +05:30
Nabin Hait
11d56903e7 Merge pull request #25415 from deepeshgarg007/bootstraped_gst_setup
feat(India): Bootstrapped GST Setup
2021-07-06 21:44:30 +05:30
Deepesh Garg
67c7067778 Merge pull request #26300 from AfshanKhan/fix-account-selection-gst-settings-v13
fix: only "Tax" type accounts should be shown for selection in GST Settings
2021-07-06 20:33:41 +05:30
Saqib
422325bb74 test: fetching of previous sle (#26352) 2021-07-06 18:37:12 +05:30
Deepesh Garg
3636efd7e6 Merge pull request #26355 from deepeshgarg007/flaky_test
test: Purchase Invoice advance test case
2021-07-06 18:22:26 +05:30
Rucha Mahabal
ad06603392 fix: removing orphaned connectors 2021-07-06 18:16:49 +05:30
Noah Jacob
5e99aa7f65 fix: stock_rbnb not defined (#26354) 2021-07-06 18:00:35 +05:30
Deepesh Garg
7f794cc0ea fix: Purchase Invoice advance test case 2021-07-06 17:58:44 +05:30
Afshan
c8eca8a448 fix: remove cancelled entries in consolidated financial statements (#26331) 2021-07-06 14:37:57 +05:30
Anurag Mishra
f0b62f70d5 fix: payroll-entry minor fix 2021-07-06 13:40:22 +05:30
Mohammed Yusuf Shaikh
842674ce79 fix: Added a message to enable appontment booking if disabled (#26334) 2021-07-06 13:34:32 +05:30
Marica
dfe11aca6a Merge pull request #26284 from marination/order-by-weightage-for-web-items
fix: Order Items by weightage in the web items query
2021-07-06 13:20:08 +05:30
rohitwaghchaure
7b781b1498 Merge pull request #26158 from marination/stock-reco-repost_qty
fix: Include Stock Reco logic in `update_qty_in_future_sle`
2021-07-06 11:22:26 +05:30
marination
57d06a86f8 chore: Test to block backdated reco causing future scarcity 2021-07-05 21:56:57 +05:30
Marica
4f51b56928 Merge branch 'version-13-hotfix' into stock-reco-repost_qty 2021-07-05 20:26:01 +05:30
marination
fa9e67502c chore: Test for backdated reco qty reposting 2021-07-05 20:23:00 +05:30
Deepesh Garg
9b6d9a41f4 fix: Test Cases 2021-07-05 17:08:27 +05:30
Deepesh Garg
15b336df28 fix: Test cases 2021-07-05 14:45:33 +05:30
marination
c69bc54297 fix: Validate LCV for Invoices without Update Stock 2021-07-05 14:24:38 +05:30
Rohit Waghchaure
5638fbb1aa fix: bom stock report not working 2021-07-05 13:54:05 +05:30
Deepesh Garg
db682d9e4c fix: Create mode of payment if doesn't exists 2021-07-05 13:46:03 +05:30
Richard Case
75fdf79376 fix: incorrect bom no. added for non-variant items on variant boms (#26320) 2021-07-05 10:56:34 +05:30
Deepesh Garg
a0599e5ac2 fix: Test cases for M-pesa 2021-07-05 10:09:42 +05:30
rohitwaghchaure
22c2d4f118 Merge pull request #26312 from rohitwaghchaure/fixed-employee-issue-in-job-card
fix: allow to make job card without employee
2021-07-04 22:58:50 +05:30
Deepesh Garg
ddf87594a1 Merge pull request #26287 from deepeshgarg007/bank_statement_import_fix
fix: Bank statement import
2021-07-04 20:34:10 +05:30
Deepesh Garg
ea5b7d38bb Merge pull request #26277 from deepeshgarg007/multi-company-deferred-revenue
fix: Auto process deferred accounting for multi-company setup
2021-07-04 20:32:22 +05:30
Deepesh Garg
cd036e115b Merge pull request #26231 from deepeshgarg007/party_dashboard
fix: Do not consider cancelled entries in party dashboard
2021-07-04 20:30:34 +05:30
Rohit Waghchaure
3105332e3c fix: allow to make job card without employee 2021-07-03 17:25:08 +05:30
Deepesh Garg
63096014a7 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into bootstraped_gst_setup 2021-07-02 20:30:18 +05:30
Rucha Mahabal
2fcd05aa82 fix: sider 2021-07-02 18:15:18 +05:30
marination
311e277204 fix: Sider 2021-07-02 18:11:13 +05:30
Anurag Mishra
73db919c99 fix: set query for training events (#26303)
* fix: set query

* fix: remove whitespace between function and params

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-07-02 17:55:42 +05:30
marination
4503a38361 fix: Handle Stock Reco cancellation and limit reposting
- Handled cancellation of reco with and without prior SLE
- Repost / Recalculate balance qty only till next stock reco
2021-07-02 17:13:45 +05:30
Afshan
b6076f772d fix: only "Tax" type accounts should be shown for selection in GST Settings 2021-07-02 15:39:16 +05:30
Ashish Shah
c0817838d9 fix: when lead is created with mobile_no, mobile_no value gets lost (#26298)
Summary: When a Lead is created with mobile_no, mobile_no value gets lost (mobile_no value is overwritten by phone value)
It is backport of https://github.com/frappe/erpnext/pull/26116

Steps to reproduce
[1]Create a Lead.
[2]Enter 
Person Name(lead_name): before_fix
Under Contact section, 
enter Phone(phone): 11 and 
Mobile No.(mobile_no):22
[3]Save it
[4] F12, 
cur_frm.doc.phone : 11 (correct)
cur_frm.doc.mobile_no : 11 (incorrect, it should be 22)
[5]Under Address & Contact section ,check contact_html it shows
before_fix
Phone: 11 (Primary label is missing)
Phone: 22 (incorrect, it should be Mobile No:22, also Primary label is missing)


Actual:
mobile_no value is lost. it is overwritten by phone value
following is image with error (before fix)
![image](https://user-images.githubusercontent.com/29812965/122664017-54b2e880-d1bc-11eb-8e4c-767a23ed7eb7.png)


Expected:
mobile_no value should be retained
following is image after fix
![image](https://user-images.githubusercontent.com/29812965/122664037-64323180-d1bc-11eb-8f6f-7628cdaa7adc.png)
2021-07-02 15:16:42 +05:30
Anupam Kumar
877597bc16 fix: feating employee in payroll entry (#26271) 2021-07-02 13:10:18 +05:30
Jannat Patel
18533e381a fix: lms progress issue (#26253) 2021-07-02 12:57:06 +05:30
Mohammed Yusuf Shaikh
ad6f20c5c7 fix: Added permission for employee to book appointment (#26255) 2021-07-02 12:32:22 +05:30
Jannat Patel
5173e74a04 fix: Project Portal Enhancements (#26290)
* fix: project portal enhancements

* fix: condition for pills
2021-07-02 11:48:46 +05:30
Deepesh Garg
d4146a91d6 Merge pull request #25323 from m1ngaa/patch-1
Delete accounts (an empty file)
2021-07-01 23:38:56 +05:30
Deepesh Garg
991d3cdd76 fix: Incorrect discount amount on amended document 2021-07-01 21:17:17 +05:30
Deepesh Garg
ba2c3c776f fix: Bank statement import 2021-07-01 18:56:51 +05:30
marination
752f099e9d fix: Order Items by weightage in the web items query 2021-07-01 17:20:24 +05:30
18alantom
865900fd2d refactor: add type hints, remove comment, sort imports 2021-07-01 14:37:37 +05:30
Anuja Pawar
d8bc514226 fix: to fetch the correct field in Tax Rule (#25927) 2021-07-01 14:06:01 +05:30
rohitwaghchaure
117cf4eca6 Merge pull request #26278 from rohitwaghchaure/fixed-employee-selection-issue-in-payroll-entry
fix: employee selection not working in payroll entry
2021-07-01 12:31:45 +05:30
rohitwaghchaure
c14fc9530c Merge pull request #26279 from rohitwaghchaure/fixed-update-cost-not-working-for-draft-bom
fix: update cost not working in the draft BOM
2021-07-01 11:57:32 +05:30
Rohit Waghchaure
a856624ccb fix: employee selection not working in payroll entry 2021-07-01 11:56:55 +05:30
Rohit Waghchaure
0bfd56e615 fix: update cost not working in the draft bom 2021-07-01 11:50:48 +05:30
Deepesh Garg
68c697b354 fix: Auto process deferred accounting for multi-company setup 2021-07-01 09:31:31 +05:30
rohitwaghchaure
d482c41eeb Merge pull request #26263 from rohitwaghchaure/fixed-removed-unused-file
fix: minor removed unused file
2021-06-30 11:36:51 +05:30
Rohit Waghchaure
815e6ec846 fix: minor removed unused file 2021-06-30 11:35:50 +05:30
rohitwaghchaure
2a1d1e1cb1 Merge pull request #26240 from rohitwaghchaure/production-plan-sub-assembly-enhancement
feat: provision to make subcontracted purchase order from the production plan
2021-06-30 11:15:11 +05:30
rohitwaghchaure
713c92e6fd Merge pull request #26259 from rohitwaghchaure/fixed-incorrect-valuation-rate-in-stock-reco
fix: incorrect valuation rate in stock reconciliation
2021-06-30 11:11:41 +05:30
Rucha Mahabal
77b0b8a877 fix: edit node button overflowing 2021-06-30 02:29:16 +05:30
Rucha Mahabal
b8a18bfef1 feat: add arc to connectors in mobile view 2021-06-30 01:57:43 +05:30
Rucha Mahabal
a7507f7af6 refactor: use arcs instead of bezier curves for cleaner connectors 2021-06-30 01:46:10 +05:30
Rohit Waghchaure
46b67b901b fix: incorrect valuation rate in stock reconciliation 2021-06-30 00:31:00 +05:30
Rucha Mahabal
7558b28b79 fix: revert changes in employee descendants query 2021-06-29 21:57:27 +05:30
Rucha Mahabal
c40b9d276e feat: setup node edit action 2021-06-29 21:51:21 +05:30
Rucha Mahabal
f15e8b7f5a refactor: add options to chart
- method to return the node data

- wrapper for showing the hierarchy
2021-06-29 21:26:47 +05:30
Deepesh Garg
a287b22b55 Merge pull request #26252 from deepeshgarg007/loan_security_pledge_on_cancel
fix: Cancellation of Loan Security Pledges
2021-06-29 20:23:46 +05:30
Rohit Waghchaure
61690775a8 feat: provision to make subcontracted purchase order from the production plan 2021-06-29 19:59:20 +05:30
Rucha Mahabal
bcc998e8c2 chore: create separate files for Desktop and Mobile view and bundle assets 2021-06-29 19:15:08 +05:30
Rucha Mahabal
b7c61ff651 fix: don't refresh connections for same node
- remove all connectors while expanding a group node
2021-06-29 18:21:42 +05:30
Rucha Mahabal
f5314293c6 feat: connectors for mobile node cards 2021-06-29 17:48:44 +05:30
Deepesh Garg
9181dde86a fix: Cancelation of Loan Security Pledges 2021-06-29 17:18:39 +05:30
Rucha Mahabal
91dcc07e26 fix: Employee Inactive status implications (#26244) 2021-06-29 15:58:46 +05:30
Rucha Mahabal
25e8723032 fix: expanded node group interactions and visibility 2021-06-29 15:06:09 +05:30
Rucha Mahabal
6e3a7b4a75 feat(mobile): sibling node group expansion and rendering 2021-06-29 11:12:47 +05:30
rohitwaghchaure
09b081ccad Merge pull request #26241 from rohitwaghchaure/fixed-allow-to-change-to-date
fix: allow user to change the To Date in the blanket order even after submit of order
2021-06-29 10:05:04 +05:30
Rohit Waghchaure
2d1c4fee1d fix: allow to changes to date in the blanket order 2021-06-29 00:33:55 +05:30
Deepesh Garg
7d7d797ffc fix: Do not consider cancelled entries in party dashboard 2021-06-28 11:24:32 +05:30
Deepesh Garg
ebc46c1e09 fix: Update account heads in GST test cases 2021-06-28 10:52:38 +05:30
Deepesh Garg
cf445eb7b4 fix: Add validate bank account method back 2021-06-26 23:59:47 +05:30
Deepesh Garg
1e5482cedd fix: Revert Changes 2021-06-26 23:49:32 +05:30
rohitwaghchaure
c1853ddf73 Merge pull request #26226 from rohitwaghchaure/fixed-removed-values-out-of-sync-on-stock-transaction-submission
fix: removed values out of sync validation from stock transactions
2021-06-26 22:28:42 +05:30
Rohit Waghchaure
170f2ad056 fix: removed values out of sync validation from stock transactions 2021-06-26 21:42:47 +05:30
rohitwaghchaure
9f051a24db Merge pull request #26213 from rohitwaghchaure/fixed-fetch-bom-items-in-stock-reco
fix: fetch batch items in stock reconciliation
2021-06-26 21:21:23 +05:30
Rohit Waghchaure
e5c47f8957 fix: fetch batch items in stock reco 2021-06-26 17:40:27 +05:30
18alantom
98c9b0e9ed refactor: remove unused func, sider fixes 2021-06-25 16:13:09 +05:30
Marica
5474c09c70 Merge pull request #25886 from ankush/work_order_flat_ops
fix: order and time of operations in multilevel BOM work order
2021-06-25 16:05:54 +05:30
Ankush Menat
9e43445f36 fix: order and time of operations for multilevel bom
- Order of operations was being sorted by idx of individual operations in
BOM table, which made the ordering useless.
- This adds ordering that's sorted from lowest level item to top level
item.
- chore: remove dead functionality. There's no `items` table. Required
  item level operations get overwritten on fetching of items /
  operations e.g. when clicking on multi-level BOM checkbox.
- test: add test for tree representation
- feat: BOMTree class to get complete representation of a tree
2021-06-25 14:44:55 +05:30
Ankush Menat
6ec8875434 fix(ux): show bom in operations child table 2021-06-25 14:44:53 +05:30
Ankush Menat
ff4aadc657 chore: remove dead and py2 compatibility code
form_grid_template doesn't exist
2021-06-25 14:43:49 +05:30
Deepesh Garg
2f0298ee11 Merge pull request #26218 from deepeshgarg007/item_tax_error_fetch
fix: Error while fetching item taxes
2021-06-25 14:00:19 +05:30
Deepesh Garg
e955a4ee72 fix: Check for is None 2021-06-25 13:38:06 +05:30
Deepesh Garg
2ca9b765ef fix: Error while fetching item taxes 2021-06-25 13:34:00 +05:30
Noah Jacob
58daf5f916 fix: precision rate for packed items (#26046) 2021-06-25 12:52:17 +05:30
Subin Tom
43f85a2877 fix: changed profitability analysis report width (#26165) 2021-06-25 11:38:11 +05:30
Alan
8958f55890 fix: add validation for 'for_qty' else throws errors (#25829)
* fix: add validation for 'for_qty' else throws errors

* fix: check if for_qty is None

* fix: check purpose

* fix: add purpose to pick list get_doc

* fix: set as read only to prevent se from picking up value

Co-authored-by: Ankush <ankushmenat@gmail.com>

* chore: undo changes to doctype modified timestamp

Co-authored-by: Ankush <ankushmenat@gmail.com>
2021-06-24 21:01:55 +05:30
Ankush
21e44b19f0 perf: don't query unless required (bp #26175)
re-order conditionals so queries are not evaluated unless required.
# Conflicts:
#	erpnext/stock/doctype/batch/batch.py
2021-06-24 20:58:07 +05:30
Deepesh Garg
b4b76b75cd Merge pull request #26176 from deepeshgarg007/item_tax_fetch_fix
fix: User is not able to change item tax template
2021-06-24 19:55:49 +05:30
Deepesh Garg
970d2af7ad Merge pull request #26211 from deepeshgarg007/include_dimension_filter
fix: Account filter not working with accounting dimension filter
2021-06-24 19:55:12 +05:30
Deepesh Garg
1564d39bf4 Merge pull request #26188 from deepeshgarg007/internal_transfer_payment_tax_v13
fix: Taxes on Internal Transfer payment entry
2021-06-24 19:51:48 +05:30
Deepesh Garg
e3ca177828 fix: Remove debug flag 2021-06-24 19:51:23 +05:30
Deepesh Garg
bdba29bab5 fix: Account filter not working with accounting dimension filter 2021-06-24 19:48:11 +05:30
Ankush
5708b7140b fix: batch nos in packed items (bp #26105)
* test: batch info in packed_items

* fix(ux): make packed items editable

* refactor: allow custom table name for set_batch

In some doctypes there are multiple child tables requiring batched
items. This change makes the function a bit more flexible.

* fix: Auto fetch batch_nos in packed_item table
2021-06-24 19:38:37 +05:30
Saqib
b3a0a7b432 fix: too many writes while renaming company abbreviation (#26203) 2021-06-24 19:30:10 +05:30
Deepesh Garg
1658107a92 fix: Linting fixes 2021-06-24 19:18:50 +05:30
Deepesh Garg
e21e435a0d fix: Add python 3 compatible string types 2021-06-24 19:17:58 +05:30
Deepesh Garg
9382b1f154 fix: Flaky test 2021-06-24 19:03:22 +05:30
Deepesh Garg
11591b3e3e Merge pull request #26202 from nextchamp-saqib/pr-item-gl-fix-v13
fix: purchase receipt gl entries with same item code
2021-06-24 18:36:23 +05:30
rohitwaghchaure
27797ffa46 Merge pull request #24523 from rohitwaghchaure/sub-operation-new-branch
Feat: Job Card Enhancements
2021-06-24 18:19:42 +05:30
Rohit Waghchaure
2330c41cca fix: total time calculation 2021-06-24 18:14:19 +05:30
Rohit Waghchaure
57307443f0 is corrective job card 2021-06-24 18:14:19 +05:30
Rohit Waghchaure
c878389050 fix: or condition filter in the get_all 2021-06-24 18:14:18 +05:30
Jannat Patel
6a9798f305 fix: update leave allocation after submit (#26191)
* fix: update leave allocation after submit v13

* fix: test

* fix: test
2021-06-24 18:11:33 +05:30
Rohit Waghchaure
fcab53b238 fix: skip job card 2021-06-24 18:07:31 +05:30
Rohit Waghchaure
6e81489095 feat: Job Card Enhancements 2021-06-24 18:07:30 +05:30
Saqib Ansari
f6dce4df73 test: service item purchase with perpetual inventory enabled 2021-06-24 17:41:52 +05:30
Saqib Ansari
1ca8f6a51d fix: purchase receipt gl entries with same item code 2021-06-24 17:41:44 +05:30
Saqib
81d164134d Merge pull request #26198 from nextchamp-saqib/pos-fixes-9-v13
refactor(pos): use pos invoice item name as unique identifier
2021-06-24 17:37:51 +05:30
Afshan
9dc625c1c9 fix: validate product bundle for existing transactions before deletion (#25978) 2021-06-24 17:36:39 +05:30
Deepesh Garg
79daed00c1 Merge pull request #26201 from noahjacob/shipping_address_fix_v13
fix: fetch preferred shipping address (bp #26132)
2021-06-24 17:35:34 +05:30
Deepesh Garg
755ebdf582 Update party.js 2021-06-24 17:35:14 +05:30
Noah Jacob
da82bd4b51 refactor: update cost updates operation time and hour rates in BOM (#25891)
* refactor: updates hour_rate and operation time on update cost

* refactor: hour_rates are updated in routing when updated in workstations

* test: test cases for updating hour_rates and operation time in linked bom
2021-06-24 17:23:21 +05:30
Noah Jacob
dbdf2515cd fix: fetches correct preferred shipping address 2021-06-24 17:06:18 +05:30
Nabin Hait
c1954ec72a Merge pull request #26195 from deepeshgarg007/deferred_revenue_error
fix: Error while booking deferred revenue
2021-06-24 15:35:02 +05:30
Saqib Ansari
3b12601461 fix: sider issues 2021-06-24 15:03:04 +05:30
Saqib Ansari
e39c3f2e69 fix: add missing semicolons 2021-06-24 15:02:59 +05:30
Saqib Ansari
ea70f6f933 fix: hide images from cart & details 2021-06-24 15:02:53 +05:30
Saqib Ansari
54cc1dedf2 refactor(pos): use pos invoice item name as unique identifier 2021-06-24 15:02:43 +05:30
Afshan
7fd44907ba feat: fetching of qty as per received qty from PR to PI (#26184) 2021-06-24 14:26:36 +05:30
Ankush
98e98d25e6 fix(Work Order): added freeze when trying to stop work order (#26192) (#26196)
* fix: added freeze when trying to stop work order

* fix(ux): add freeze message

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-06-24 14:24:28 +05:30
Deepesh Garg
ca2e914715 fix: Error while booking deferred revenue 2021-06-24 14:14:46 +05:30
Marica
ce99701150 Merge pull request #26170 from marination/web-item-group
fix: Website item group logic for product listing in Item Group pages
2021-06-24 13:28:18 +05:30
marination
a4f5dcaa9a chore: Test for Item visibility in multiple item group pages 2021-06-24 13:08:20 +05:30
Marica
6b15a05de4 Merge pull request #26187 from marination/country-modal-cart
fix: Address Card issues in e-commerce
2021-06-24 12:25:21 +05:30
Deepesh Garg
437e972108 Merge pull request #26143 from deepeshgarg007/gstr_1_export_invoices_error
fix: Export invoices not visible in GSTR-1 report
2021-06-24 12:15:29 +05:30
Deepesh Garg
9d8e8f8bdf fix: Do not show received amount after tax for internal tarnsfers 2021-06-24 12:02:39 +05:30
Deepesh Garg
bd9317956b fix: Taxes on Internal Transfer payment entry 2021-06-24 12:02:32 +05:30
marination
bbe64b5604 fix: (style) Address card buttons hover state 2021-06-24 12:01:12 +05:30
Rucha Mahabal
a9b5dc6030 fix: chart not visible for First Response Time reports (#26032) (#26185) 2021-06-24 11:53:28 +05:30
marination
f5fa1ee4b6 fix: Country Link field in 'Add address' website modal auto-clears 2021-06-24 11:03:32 +05:30
Deepesh Garg
5e49bee755 Merge pull request #26083 from deepeshgarg007/payroll_accounting_dimension
fix: Accounting Dimensions for payroll entry accrual Journal Entry
2021-06-24 10:38:42 +05:30
Deepesh Garg
03b629c851 Merge pull request #26100 from deepeshgarg007/pi_billing_address
fix: Billing address not fetched in Purchase Invoice
2021-06-24 10:29:01 +05:30
Deepesh Garg
4cf0b02ddc Merge pull request #26095 from deepeshgarg007/sales_order_billed_qty
fix: Incorrect billed qty in Sales Order analytics
2021-06-24 10:21:57 +05:30
Deepesh Garg
3007c9900b Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into payroll_accounting_dimension 2021-06-23 23:06:15 +05:30
Deepesh Garg
7e006496dd fix: Check if item tax template exists 2021-06-23 22:52:51 +05:30
Deepesh Garg
c9c1d10435 fix: Make item tax templates optional 2021-06-23 22:47:29 +05:30
Deepesh Garg
1f7b95f390 fix: User is not able to change item tax template 2021-06-23 20:56:27 +05:30
marination
078826d510 fix: Sider 2021-06-23 20:12:59 +05:30
marination
f913e0dd05 fix: Consider Table Multiselect fields in Query engine
- Since table multiselect fields were not handled, the query tried searching for this child field in item master
- This broke the query
- On trying to reload or go back to all-products page with field filters that are table mutiselect, page breaks
2021-06-23 20:06:11 +05:30
rohitwaghchaure
b4863bfa50 Merge pull request #25696 from rohitwaghchaure/incorrect-serial-no-qty-valuation-report
feat: Incorrect valuation rate report for serialized items
2021-06-23 16:52:51 +05:30
marination
1b9b72d12e fix: Filters did not consider Website Item Group 2021-06-23 16:03:24 +05:30
Deepesh Garg
0bfffddac4 fix: Test Cases 2021-06-23 15:37:17 +05:30
marination
d802d73973 fix: Consider Website Item Groups in Item group page product listing
- Passed an argument to query engine to know when query is for item group page
- If for item group page, get data with regards to website item group table
- This query should be fast since there's one filter and that shortens the table beforehand
- This data is merged with the results from the Item master (results only considering item attributes and field filters)
- The combined data is then sorted as per weightage

Co-authored-by: Gavin D'souza <gavin18d@gmail.com>
2021-06-23 14:24:13 +05:30
Jannat Patel
9ec0ded28f fix: Staffing plan vacancies data type issue (#25941)
* fix: staffing plan vacancies data type issue

* fix: translation issue

* fix: removed greater than 0 condition
2021-06-23 14:05:10 +05:30
Deepesh Garg
35e11fbea6 fix: Tests 2021-06-23 13:17:01 +05:30
Deepesh Garg
208b5f9e73 chore: Add comments 2021-06-23 12:44:56 +05:30
Deepesh Garg
40a4330ec1 fix: Move tax categories up in country wise json 2021-06-23 12:38:37 +05:30
Jannat Patel
44815393b3 fix: job applicant link issue (#25934) 2021-06-23 12:28:02 +05:30
Deepesh Garg
673470705b Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into bootstraped_gst_setup 2021-06-23 11:33:15 +05:30
Anurag Mishra
fc98abece9 feat: Employee Grievance (#25705)
* feat: Employee Grievance

* feat: link to desk and automatic unsuspend

* test: Employee Grievance

* fix: Sider and Translation

* fix: sider

* fix: formatting

* feat: changes requested

* feat: Employee Grievance

* feat: link to desk and automatic unsuspend

* test: Employee Grievance

* fix: Sider and Translation

* fix: sider

* fix: formatting

* feat: changes requested

* fix: patch test and sider issue

* fix: make Employee Responsible non-mandatory since there cannot be an employee responsible for all sorts of grievances

- show pay cut and suspension buttons only if Employee Resposible is set

- some label changes

* feat: added subject field for more context

- set title for documents

- added list view settings

- refactor suspend and unsuspend functions

- add submit and cancel perms for system and hr managers

- fix tests

* fix: sider issues

* fix: removed suspension and paycut

* fix:sider

* fix: test

* fix: test

* fix: resolved Conflicts

* fix: sider

* fix: remove debugging print statements

* fix: validation message

* fix: unnecessary comma

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-06-23 11:21:38 +05:30
marination
ea2c02738d fix: Include Stock Reco logic in update_qty_in_future_sle 2021-06-22 21:44:50 +05:30
Noah Jacob
c05496a5a7 fix: fixed rounding off ordered percent to 100 in condition (#26152) 2021-06-22 17:53:53 +05:30
Subin Tom
219a87d530 fix: disable sales order cancellation if linked to draft invoice (#26125) 2021-06-22 16:28:58 +05:30
Subin Tom
889140fd8c fix: sql syntax error in get_project_name method (#26147) 2021-06-22 16:26:19 +05:30
Deepesh Garg
cfdda21dd2 fix: Export invoices not visible in GSTR-1 report 2021-06-22 13:03:22 +05:30
Marica
703c30f5f8 fix: Consistent alert indicators 2021-06-22 11:20:17 +05:30
Marica
9f15ebe711 Merge pull request #26134 from marination/product-weightage
fix: Sort website products by weightage mentioned in Item master
2021-06-22 11:16:20 +05:30
Rucha Mahabal
cce19db826 feat: org chart mobile interactions 2021-06-21 21:55:50 +05:30
marination
f97206b3cb fix: Sort website products by weightage mentioned in Item master 2021-06-21 19:38:37 +05:30
marination
ea0dea46e0 fix: sider and semgrep 2021-06-21 16:51:12 +05:30
marination
49ec0e5ac3 feat: Optionally allow rejected quality inspection on submission 2021-06-21 16:18:35 +05:30
rohitwaghchaure
d6eacf556d Merge pull request #26126 from rohitwaghchaure/production-plan-fix-to-show-parent-warehouse
fix: allow to select group warehouse while downloading materials from production plan
2021-06-21 15:39:13 +05:30
rohitwaghchaure
8347eb1dba Update production_plan.js 2021-06-21 15:38:44 +05:30
Rohit Waghchaure
773aabae44 fix: allow to select group warehouse while downloading materials from production plan 2021-06-21 14:54:27 +05:30
rohitwaghchaure
3956f82e7c Merge pull request #26122 from rohitwaghchaure/fix-rate-not-able-to-change
fix: rate not able to change in purchase order
2021-06-21 13:40:29 +05:30
Ankush
e78364c191 fix: status indicator for delivery notes (#26062)
On list view `per_returned` isn't fetched i.e. `undefined` which become
0 hence the list view indicator is false.

This "computation" is already done by status updater, so relying on
doc.status is better than redefining it.
2021-06-21 11:15:16 +05:30
Saqib
4b32ccb124 fix(pos): unsupported operand type -=: for 'float' and 'NoneType' (#26097) 2021-06-21 10:49:25 +05:30
Saqib
fb89008a13 fix(pos): unsupported operand type -=: for 'float' and 'NoneType' (#26097) 2021-06-21 10:49:09 +05:30
Rohit Waghchaure
582f187726 fix: rate not able to change in purchase order 2021-06-21 00:59:02 +05:30
rohitwaghchaure
ab3cd7e283 Merge pull request #26023 from rohitwaghchaure/fixed-linking-between-mr-and-sq
fix: material request and supplier quotation not linked if supplier quotation created from supplier portal
2021-06-20 15:16:32 +05:30
Rucha Mahabal
c1ba35b25b feat: Organizational Chart 2021-06-20 12:42:06 +05:30
Marica
29a1a8d2d6 Merge pull request #25878 from rohitwaghchaure/v13-sub-contract-enhancemnet
feat: subcontract code refactor and enhancement
2021-06-20 11:54:23 +05:30
Rohit Waghchaure
3d7f660bec fix: test case for Project Profitability report 2021-06-20 10:20:35 +05:30
Rohit Waghchaure
f5db407461 fix: available qty for consumption 2021-06-19 23:19:45 +05:30
Rohit Waghchaure
5cc3f14506 fix: purchase invoice qty change not recalculate the consumed qty and added test cases for purchase invoice 2021-06-19 23:16:23 +05:30
Rohit Waghchaure
ddb0ec261a fix: code cleanup and convert public method to private for subcontracting class 2021-06-19 23:16:23 +05:30
Rohit Waghchaure
2fb5291785 fix: toggle consumed qty field based on condition 2021-06-19 23:16:22 +05:30
Rohit Waghchaure
9a2db0b5b1 fix: semgrep error 2021-06-19 23:16:22 +05:30
Rohit Waghchaure
a94b89727c feat: subcontract code refactor and enhancement 2021-06-19 23:16:22 +05:30
rohitwaghchaure
a2bb1b8acd Merge pull request #26081 from rohitwaghchaure/fixed-stock-entry-submission-performance
fix: time out while submit / cancel the stock transactions with more than 50 Items
2021-06-19 16:14:14 +05:30
Rohit Waghchaure
8c844e4515 fix: material request and supplier quotation not linked if sq created from supplier portal against rfq 2021-06-19 16:08:26 +05:30
Rohit Waghchaure
8520edc952 fix: time out while submitting the stock transactions with more than 50 items 2021-06-19 00:55:35 +05:30
Deepesh Garg
be881c743e Merge pull request #26108 from deepeshgarg007/loan_repay_via_salary_v13
fix: Sanctioned loan amount limit check
2021-06-18 23:30:29 +05:30
Deepesh Garg
81c97c13ce fix: Sanctioned loan amount limit check 2021-06-18 19:57:53 +05:30
Anurag Mishra
ef6e005c04 Merge pull request #26071 from Anurag810/training_event_fixes_2.0
fix: Training event
2021-06-18 15:44:56 +05:30
Ganga Manoj
3d8f82459b fix(Issue): reset response_by and resolution_by if SLA is removed (#25997) 2021-06-18 11:42:28 +05:30
Anuja Pawar
b066fe9519 fix: insufficient permission for dunning error (#26092) 2021-06-18 11:29:07 +05:30
Deepesh Garg
a58b571ccb fix: Billing address not fetched in Purchase Invoice 2021-06-18 10:45:35 +05:30
rohitwaghchaure
3bb9f4a742 Merge pull request #26098 from rohitwaghchaure/enqueue-cancel-action-in-stock-reco
fix: timeout while cancelling stock reconciliation
2021-06-18 10:44:59 +05:30
Rohit Waghchaure
ef97269386 fix: timeout while cancelling stock reconciliation 2021-06-18 10:11:53 +05:30
Deepesh Garg
59e2e4989b fix: Incorrect billed qty in Sales Order analytics 2021-06-17 19:58:16 +05:30
Eben van Deventer
ddef85ae97 fix: Correct South Africa VAT Rate (#25894)
On 1 April 2018 South Africa increased the VAT rate from 14% to 15%, this proposed change seeks to update the default parameters for a fresh ERPNext installation.
2021-06-17 18:43:30 +05:30
Alan
f9390f596d fix: auto unlink warehouse from item on delete (#26073)
* fix: auto unlink warehouse from item on delete

* fix: sider

* refactor: use delete_doc

* test: add test for unlinking warehouse from item

* refactor: add msgprint to inform user of unlink

* refactor: cleanup and reuse extant functions

* fix: don't delete row, update table
2021-06-17 18:13:23 +05:30
Deepesh Garg
d3ccb024f8 Merge pull request #26078 from nemesis189/fixed-label-rate-for-purchase-invoice-item-v13
fix: removed extra space from label rate
2021-06-17 17:19:17 +05:30
Deepesh Garg
510077b3d4 fix(minor): Translation and linting issues 2021-06-17 11:21:21 +05:30
Deepesh Garg
b8442816ca Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into payroll_accounting_dimension 2021-06-17 11:19:12 +05:30
Deepesh Garg
913e92c29f Merge pull request #26044 from GangaManoj/account-multiselect-gl
feat(General Ledger): Implement multi-account selection
2021-06-16 22:33:50 +05:30
Deepesh Garg
5c19a9251f fix: Accouting Dimensions for payroll entry accrual Journal Entry 2021-06-16 22:14:29 +05:30
Subin Tom
6f9de8c86f fix: removed extra space from label rate 2021-06-16 20:01:29 +05:30
GangaManoj
41b7c1aec0 fix(General Ledger): Improve account filter 2021-06-16 14:40:14 +05:30
Afshan
3b1b4684ba fix: check for duplicate payment terms in Payment Term Template (#26003) 2021-06-16 14:30:45 +05:30
Afshan
8c73f6f19e fix(pos): pos loyalty card alignment (#26051) 2021-06-16 14:28:26 +05:30
Saqib
60ce00531d fix: label for enabling ledger posting of change amount (#26070) 2021-06-16 14:25:55 +05:30
GangaManoj
86f689e54a fix(General Ledger): Get account_currency accurately 2021-06-16 14:23:02 +05:30
Anurag Mishra
b1c72da7d7 fix: Training event 2021-06-16 14:08:32 +05:30
Saqib
1fd80992d7 fix(pos): 'NoneType' object is not iterable (#26066) 2021-06-16 13:27:34 +05:30
Deepesh Garg
d70c6996f2 Merge pull request #25951 from nextchamp-saqib/invoice-opening-pnl-validation
fix: opening invoices can alter profit and loss of a closed year
2021-06-16 10:52:40 +05:30
GangaManoj
53a9ac4466 fix(General Ledger): Condense account_conditions 2021-06-16 04:10:29 +05:30
GangaManoj
79dc0f0afc fix: Remove console.log() 2021-06-16 03:37:11 +05:30
Deepesh Garg
fb9cb78980 Merge pull request #26045 from GangaManoj/filter-cc-project
fix(General Ledger): Filter Cost Center and Project drop-down lists by Company
2021-06-15 21:18:49 +05:30
Noah Jacob
b5a1491176 fix: escaped warehouse value for sql query (#26049) 2021-06-15 12:44:04 +05:30
Deepesh Garg
5149101045 Merge pull request #26037 from deepeshgarg007/payment_entry_auto_tax_fixes
fix: Auto tax calculations in Payment Entry
2021-06-14 20:39:41 +05:30
Deepesh Garg
4cd0f6ce23 fix: Revert unintended changes 2021-06-14 20:01:04 +05:30
Deepesh Garg
cf1fc40b06 Merge pull request #25906 from deepeshgarg007/gst_taxtable_value_with_discount
fix(India): Taxable value for invoices with additional discount
2021-06-14 17:11:08 +05:30
GangaManoj
75b30efb05 fix(General Ledger): Filter Project drop-down list by Company 2021-06-14 16:42:27 +05:30
GangaManoj
27ec51f021 fix(General Ledger): Filter Cost Center drop-down list by Company 2021-06-14 16:41:56 +05:30
Marica
18833b5ea1 Merge pull request #26043 from marination/subcontracted-rm-transfer-report-test
fix: Flaky test for Report Subcontracted Raw materials to be transferred
2021-06-14 15:25:05 +05:30
marination
3b070d1b05 fix: Flaky test for Report Subcontracted Raw materials to be transferred 2021-06-14 14:51:33 +05:30
Deepesh Garg
9eac4d0af6 fix: Import throw 2021-06-14 14:44:19 +05:30
Deepesh Garg
8718013c96 fix: Add separate function to validate payment entry taxes 2021-06-14 14:34:44 +05:30
GangaManoj
0511ffcf30 fix(General Ledger): Implement multi-account selection 2021-06-14 13:22:44 +05:30
Nabin Hait
ad58182395 Merge pull request #26030 from ruchamahabal/add-inactive-status-to-employee-v13
feat: add Inactive status to Employee
2021-06-14 12:33:28 +05:30
Deepesh Garg
856484aeb0 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into gst_taxtable_value_with_discount 2021-06-14 11:29:41 +05:30
Deepesh Garg
580346360f fix: Auto tax calculations in Payment Entry 2021-06-14 11:16:39 +05:30
Anoop
28cdff10cf fix: update linked Customer on Patient update only if Link Customer to Patient is enabled (#25926) 2021-06-12 14:17:04 +05:30
Rucha Mahabal
cf349aadf9 fix: unable to enter score in Assessment Result details grid (#25945) (#26031) 2021-06-12 14:05:12 +05:30
Rucha Mahabal
17550fb4bf feat: add Inactive status to Employee 2021-06-12 13:36:47 +05:30
Anupam Kumar
400205cc8a fix: payroll entry employee detail issue (#25968)
* fix: payroll entry employee detail issue

* fix: review changes
2021-06-12 12:30:53 +05:30
Marica
d7d5c4c329 Merge pull request #26011 from marination/subcontracted-rm-to-transfer-report
fix: Report Subcontracted Raw Materials to be Transferred
2021-06-11 17:50:30 +05:30
marination
c4d851e45f fix: Test 2021-06-11 17:27:43 +05:30
Ankush Menat
a9c84f749a perf(minor): remove unnecessary comprehensions (#25645) 2021-06-11 16:00:48 +05:30
Ankush Menat
5bb89b0ead test(perf): eliminate repeat creation of HSN codes (#25947) 2021-06-11 15:57:01 +05:30
marination
ec4a3723cc fix: Sider 2021-06-11 12:47:06 +05:30
marination
687ad9b942 fix: Report Raw Materials to be Transferred 2021-06-10 21:18:19 +05:30
Deepesh Garg
88176e65e4 fix: Check for gst_hsn_code 2021-06-10 17:31:28 +05:30
Deepesh Garg
701cba7f03 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into gst_taxtable_value_with_discount 2021-06-10 12:04:38 +05:30
Deepesh Garg
edecd5b0c6 fix: Update einvoice json test 2021-06-10 12:04:30 +05:30
18alantom
6f79c4c348 fix: add account filter 2021-06-07 13:58:45 +05:30
18alantom
23b907df1a fix: use stock value diff for calculation 2021-06-07 13:52:26 +05:30
18alantom
672c8bb112 feature: report for cost of goods sold by item group 2021-06-04 16:44:30 +05:30
Saqib Ansari
48036b4bab fix: invoices can alter profit and loss of a closed year 2021-06-04 09:54:34 +05:30
Deepesh Garg
7c7c084159 fix: Check for tax category 2021-06-02 14:12:28 +05:30
Deepesh Garg
ca34eec2d6 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into bootstraped_gst_setup 2021-06-02 13:26:27 +05:30
Deepesh Garg
b3ed807b70 fix: Regional settings setup 2021-06-02 13:26:21 +05:30
Deepesh Garg
c6dcc9d94a fix(India): Taxable value for invoices with additional discount 2021-06-01 13:13:04 +05:30
Rohit Waghchaure
6432aaa07a feat: added reports to check incorrect qty and valuation for serialized items 2021-06-01 12:46:43 +05:30
Deepesh Garg
48b1a82fa1 fix: Add accounts and templates for reverse charge 2021-05-29 23:54:51 +05:30
Deepesh Garg
4311fdc3a1 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into bootstraped_gst_setup 2021-05-27 17:49:23 +05:30
Deepesh Garg
0ae702aab9 Merge branch 'develop' of https://github.com/frappe/erpnext into bootstraped_gst_setup 2021-05-02 22:37:04 +05:30
Deepesh Garg
1bac72b74d fix: Add GST accounts to GST Settings 2021-05-02 22:29:48 +05:30
Deepesh Garg
72e602ae54 fix: Add validation for GST Settings 2021-05-02 18:22:29 +05:30
Deepesh Garg
f6610c96dd fix: Gracefully handle duplicate bank account name to make setup faster 2021-05-02 12:23:11 +05:30
Deepesh Garg
a66184fe3c fix: Remove redundant get_doc 2021-05-02 12:22:16 +05:30
Deepesh Garg
204ea1027f fix: Ignore validations for Tax Setup 2021-04-30 16:35:52 +05:30
Deepesh Garg
66a71bdd1a fix: Issues on new company setup 2021-04-21 20:42:20 +05:30
Deepesh Garg
50997709d5 fix: Update country-wise-tax JSON and tax setup 2021-04-21 20:41:57 +05:30
Deepesh Garg
2acc66db2c fix: Add tax categories on company setup 2021-04-21 11:49:02 +05:30
Deepesh Garg
3130ed52ff fix: Item Tax templates for GST 2021-04-20 23:23:07 +05:30
Deepesh Garg
e379f083bb feat(India): Separate Input and Output GST tax accounts 2021-04-20 23:04:39 +05:30
m1ngaa
f68205468c Delete accounts (an empty file)
This file has no purpose, and must've been included as a tiny mistake..?
2021-04-14 05:50:31 +08:00
Anupam Kumar
f52f2b2f17 Merge branch 'develop' into email-digest 2021-04-09 17:24:43 +05:30
Anupam Kumar
281eade019 Merge branch 'develop' into email-digest 2021-04-08 10:58:33 +05:30
Anupam
e711b30f66 fix: resolved conflicts 2021-04-05 17:06:59 +05:30
Marica
052a2767f0 Merge branch 'develop' into email-digest 2021-02-17 11:21:14 +05:30
Marica
83be34fa07 Merge branch 'develop' into email-digest 2021-01-19 21:14:07 +05:30
Marica
e34f3364d0 Merge branch 'develop' into email-digest 2021-01-13 12:03:03 +05:30
Anupam
5abb997a27 fix: resolved conflicts 2021-01-13 11:11:22 +05:30
Anupam
d4e2a3324f fix: review fixes 2020-10-13 12:26:25 +05:30
Anupam Kumar
68b069983d Merge branch 'develop' into email-digest 2020-09-07 20:22:25 +05:30
Anupam Kumar
3775324441 Merge branch 'develop' into email-digest 2020-09-06 21:49:43 +05:30
Anupam K
38999efb4f Merge branch 'email-digest' of https://github.com/anupamvs/erpnext into email-digest 2020-08-31 16:55:40 +05:30
Anupam K
8d0de8c311 Merge branch 'develop' of https://github.com/frappe/erpnext into email-digest 2020-08-31 16:54:36 +05:30
Anupam K
ddfc104239 fix: patch 2020-08-31 16:54:16 +05:30
Anupam Kumar
57321d085c Merge branch 'develop' into email-digest 2020-08-31 16:24:29 +05:30
Anupam K
01b37ad704 fix: multiselect recipients in Email Digest 2020-08-25 08:39:26 +05:30
522 changed files with 19214 additions and 8960 deletions

View File

@@ -147,10 +147,15 @@
"Chart": true,
"Cypress": true,
"cy": true,
"describe": true,
"expect": true,
"it": true,
"context": true,
"before": true,
"beforeEach": true,
"onScan": true
"onScan": true,
"html2canvas": true,
"extend_cscript": true,
"localforage": true
}
}

View File

@@ -42,5 +42,5 @@ sed -i 's/socketio:/# socketio:/g' Procfile
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
bench get-app erpnext "${GITHUB_WORKSPACE}"
bench start &
bench start &> bench_run_logs.txt &
bench --site test_site reinstall --yes

View File

@@ -98,8 +98,6 @@ rules:
languages: [python]
severity: WARNING
paths:
exclude:
- test_*.py
include:
- "*/**/doctype/*"

View File

@@ -8,18 +8,3 @@ rules:
dynamic content. Avoid it or use safe_eval().
languages: [python]
severity: ERROR
- id: frappe-sqli-format-strings
patterns:
- pattern-inside: |
@frappe.whitelist()
def $FUNC(...):
...
- pattern-either:
- pattern: frappe.db.sql("..." % ...)
- pattern: frappe.db.sql(f"...", ...)
- pattern: frappe.db.sql("...".format(...), ...)
message: |
Detected use of raw string formatting for SQL queries. This can lead to sql injection vulnerabilities. Refer security guidelines - https://github.com/frappe/erpnext/wiki/Code-Security-Guidelines
languages: [python]
severity: WARNING

View File

@@ -1,16 +1,25 @@
name: Backport
on:
pull_request:
pull_request_target:
types:
- closed
- labeled
jobs:
backport:
runs-on: ubuntu-18.04
name: Backport
main:
runs-on: ubuntu-latest
steps:
- name: Backport
uses: tibdex/backport@v1
- name: Checkout Actions
uses: actions/checkout@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
repository: "frappe/backport"
path: ./actions
ref: develop
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run backport
uses: ./actions/backport
with:
token: ${{secrets.BACKPORT_BOT_TOKEN}}
labelsToAdd: "backport"
title: "{{originalTitle}}"

View File

@@ -1,34 +1,18 @@
name: Semgrep
on:
pull_request:
branches:
- develop
- version-13-hotfix
- version-13-pre-release
pull_request: { }
jobs:
semgrep:
name: Frappe Linter
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup python3
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Setup semgrep
run: |
python -m pip install -q semgrep
git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF -q
- name: Semgrep errors
run: |
files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
[[ -d .github/helper/semgrep_rules ]] && semgrep --severity ERROR --config=.github/helper/semgrep_rules --quiet --error $files
semgrep --config="r/python.lang.correctness" --quiet --error $files
- name: Semgrep warnings
run: |
files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF)
[[ -d .github/helper/semgrep_rules ]] && semgrep --severity WARNING --severity INFO --config=.github/helper/semgrep_rules --quiet $files
- uses: actions/checkout@v2
- uses: returntocorp/semgrep-action@v1
env:
SEMGREP_TIMEOUT: 120
with:
config: >-
r/python.lang.correctness
.github/helper/semgrep_rules

108
.github/workflows/ui-tests.yml vendored Normal file
View File

@@ -0,0 +1,108 @@
name: UI
on:
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-18.04
strategy:
fail-fast: false
name: UI Tests (Cypress)
services:
mysql:
image: mariadb:10.3
env:
MYSQL_ALLOW_EMPTY_PASSWORD: YES
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
steps:
- name: Clone
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.7
- uses: actions/setup-node@v2
with:
node-version: 14
check-latest: true
- name: Add to Hosts
run: |
echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache cypress binary
uses: actions/cache@v2
with:
path: ~/.cache
key: ${{ runner.os }}-cypress-
restore-keys: |
${{ runner.os }}-cypress-
${{ runner.os }}-
- name: Install
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
env:
DB: mariadb
TYPE: ui
- name: Site Setup
run: cd ~/frappe-bench/ && bench --site test_site execute erpnext.setup.utils.before_tests
- name: cypress pre-requisites
run: cd ~/frappe-bench/apps/frappe && yarn add cypress-file-upload@^5 --no-lockfile
- name: Build Assets
run: cd ~/frappe-bench/ && bench build
- name: UI Tests
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless
env:
CYPRESS_RECORD_KEY: 60a8e3bf-08f5-45b1-9269-2b207d7d30cd
- name: Show bench console if tests failed
if: ${{ failure() }}
run: cat ~/frappe-bench/bench_run_logs.txt

View File

@@ -3,16 +3,33 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
manufacturing/ @rohitwaghchaure @marination
accounts/ @deepeshgarg007 @nextchamp-saqib
loan_management/ @deepeshgarg007 @rohitwaghchaure
pos* @nextchamp-saqib @rohitwaghchaure
assets/ @nextchamp-saqib @deepeshgarg007
stock/ @marination @rohitwaghchaure
buying/ @marination @deepeshgarg007
hr/ @Anurag810 @rohitwaghchaure
projects/ @hrwX @nextchamp-saqib
support/ @hrwX @marination
healthcare/ @ruchamahabal @marination
erpnext_integrations/ @Mangesh-Khairnar @nextchamp-saqib
requirements.txt @gavindsouza
erpnext/accounts/ @nextchamp-saqib @deepeshgarg007
erpnext/assets/ @nextchamp-saqib @deepeshgarg007
erpnext/erpnext_integrations/ @nextchamp-saqib
erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007
erpnext/regional @nextchamp-saqib @deepeshgarg007
erpnext/selling @nextchamp-saqib @deepeshgarg007
erpnext/support/ @nextchamp-saqib @deepeshgarg007
pos* @nextchamp-saqib
erpnext/buying/ @marination @rohitwaghchaure @ankush
erpnext/e_commerce/ @marination
erpnext/maintenance/ @marination @rohitwaghchaure
erpnext/manufacturing/ @marination @rohitwaghchaure @ankush
erpnext/portal/ @marination
erpnext/quality_management/ @marination @rohitwaghchaure
erpnext/shopping_cart/ @marination
erpnext/stock/ @marination @rohitwaghchaure @ankush
erpnext/crm/ @ruchamahabal @pateljannat
erpnext/education/ @ruchamahabal @pateljannat
erpnext/healthcare/ @ruchamahabal @pateljannat @chillaranand
erpnext/hr/ @ruchamahabal @pateljannat
erpnext/non_profit/ @ruchamahabal
erpnext/payroll @ruchamahabal @pateljannat
erpnext/projects/ @ruchamahabal @pateljannat
erpnext/controllers @deepeshgarg007 @nextchamp-saqib @rohitwaghchaure @marination
.github/ @surajshetty3416 @ankush
requirements.txt @gavindsouza

11
cypress.json Normal file
View File

@@ -0,0 +1,11 @@
{
"baseUrl": "http://test_site:8000",
"projectId": "da59y9",
"adminPassword": "admin",
"defaultCommandTimeout": 20000,
"pageLoadTimeout": 15000,
"retries": {
"runMode": 2,
"openMode": 2
}
}

View File

@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -0,0 +1,13 @@
context('Customer', () => {
before(() => {
cy.login();
});
it('Check Customer Group', () => {
cy.visit(`app/customer/`);
cy.get('.primary-action').click();
cy.wait(500);
cy.get('.custom-actions > .btn').click();
cy.get_field('customer_group', 'Link').should('have.value', 'All Customer Groups');
});
});

View File

@@ -0,0 +1,111 @@
context('Organizational Chart', () => {
before(() => {
cy.login();
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Frappe-CSRF-Token': csrf_token
},
timeout: 60000
}).then(res => {
expect(res.status).eq(200);
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.blur({ force: true });
});
});
});
it('renders root nodes and loads children for the first expandable node', () => {
// check rendered root nodes and the node name, title, connections
cy.get('.hierarchy').find('.root-level ul.node-children').children()
.should('have.length', 2)
.first()
.as('first-child');
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2 Connections');
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// children of 1st root visible
cy.get(`div[data-parent="${employee_records.message[0]}"]`).as('child-node');
cy.get('@child-node')
.should('have.length', 1)
.should('be.visible');
cy.get('@child-node').get('.node-name').contains('Test Employee 3');
// connectors between first root node and immediate child
cy.get(`path[data-parent="${employee_records.message[0]}"]`)
.should('be.visible')
.invoke('attr', 'data-child')
.should('equal', employee_records.message[2]);
});
});
it('hides active nodes children and connectors on expanding sibling node', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click sibling
cy.get(`#${employee_records.message[1]}`)
.click()
.should('have.class', 'active');
// child nodes and connectors hidden
cy.get(`[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
cy.get(`path[data-parent="${employee_records.message[0]}"]`).should('not.be.visible');
});
});
it('collapses previous level nodes and refreshes connectors on expanding child node', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// click child node
cy.get(`#${employee_records.message[3]}`)
.click()
.should('have.class', 'active');
// previous level nodes: parent should be on active-path; other nodes should be collapsed
cy.get(`#${employee_records.message[0]}`).should('have.class', 'collapsed');
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
// previous level connectors refreshed
cy.get(`path[data-parent="${employee_records.message[1]}"]`)
.should('have.class', 'collapsed-connector');
// child node's children and connectors rendered
cy.get(`[data-parent="${employee_records.message[3]}"]`).should('be.visible');
cy.get(`path[data-parent="${employee_records.message[3]}"]`).should('be.visible');
});
});
it('expands previous level nodes', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`)
.click()
.should('have.class', 'active');
cy.get(`[data-parent="${employee_records.message[0]}"]`)
.should('be.visible');
cy.get('ul.hierarchy').children().should('have.length', 2);
cy.get(`#connectors`).children().should('have.length', 1);
});
});
it('edit node navigates to employee master', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
cy.url().should('include', `/employee/${employee_records.message[0]}`);
});
});
});

View File

@@ -0,0 +1,190 @@
context('Organizational Chart Mobile', () => {
before(() => {
cy.login();
cy.viewport(375, 667);
cy.visit('/app/website');
cy.awesomebar('Organizational Chart');
cy.window().its('frappe.csrf_token').then(csrf_token => {
return cy.request({
url: `/api/method/erpnext.tests.ui_test_helpers.create_employee_records`,
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Frappe-CSRF-Token': csrf_token
},
timeout: 60000
}).then(res => {
expect(res.status).eq(200);
cy.get('.frappe-control[data-fieldname=company] input').focus().as('input');
cy.get('@input')
.clear({ force: true })
.type('Test Org Chart{enter}', { force: true })
.blur({ force: true });
});
});
});
it('renders root nodes', () => {
// check rendered root nodes and the node name, title, connections
cy.get('.hierarchy-mobile').find('.root-level').children()
.should('have.length', 2)
.first()
.as('first-child');
cy.get('@first-child').get('.node-name').contains('Test Employee 1');
cy.get('@first-child').get('.node-info').find('.node-title').contains('CEO');
cy.get('@first-child').get('.node-info').find('.node-connections').contains('· 2');
});
it('expands root node', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[1]}`)
.click()
.should('have.class', 'active');
// other root node removed
cy.get(`#${employee_records.message[0]}`).should('not.exist');
// children of active root node
cy.get('.hierarchy-mobile').find('.level').first().find('ul.node-children').children()
.should('have.length', 2);
cy.get(`div[data-parent="${employee_records.message[1]}"]`).first().as('child-node');
cy.get('@child-node').should('be.visible');
cy.get('@child-node')
.get('.node-name')
.contains('Test Employee 4');
// connectors between root node and immediate children
cy.get(`path[data-parent="${employee_records.message[1]}"]`).as('connectors');
cy.get('@connectors')
.should('have.length', 2)
.should('be.visible');
cy.get('@connectors')
.first()
.invoke('attr', 'data-child')
.should('eq', employee_records.message[3]);
});
});
it('expands child node', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[3]}`)
.click()
.should('have.class', 'active')
.as('expanded_node');
// 2 levels on screen; 1 on active path; 1 collapsed
cy.get('.hierarchy-mobile').children().should('have.length', 2);
cy.get(`#${employee_records.message[1]}`).should('have.class', 'active-path');
// children of expanded node visible
cy.get('@expanded_node')
.next()
.should('have.class', 'node-children')
.as('node-children');
cy.get('@node-children').children().should('have.length', 1);
cy.get('@node-children')
.first()
.get('.node-card')
.should('have.class', 'active-child')
.contains('Test Employee 7');
// orphan connectors removed
cy.get(`#connectors`).children().should('have.length', 2);
});
});
it('renders sibling group', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[1]}`)
.next()
.as('sibling_group');
cy.get('@sibling_group')
.should('have.attr', 'data-parent', 'undefined')
.should('have.class', 'node-group')
.and('have.class', 'collapsed');
cy.get('@sibling_group').get('.avatar-group').children().as('siblings');
cy.get('@siblings').should('have.length', 1);
cy.get('@siblings')
.first()
.should('have.attr', 'title', 'Test Employee 1');
});
});
it('expands previous level nodes', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[6]}`)
.click()
.should('have.class', 'active');
// clicking on previous level node should remove all the nodes ahead
// and expand that node
cy.get(`#${employee_records.message[3]}`).click();
cy.get(`#${employee_records.message[3]}`)
.should('have.class', 'active')
.should('not.have.class', 'active-path');
cy.get(`#${employee_records.message[6]}`).should('have.class', 'active-child');
cy.get('.hierarchy-mobile').children().should('have.length', 2);
cy.get(`#connectors`).children().should('have.length', 2);
});
});
it('expands sibling group', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
// sibling group visible for parent
cy.get(`#${employee_records.message[6]}`).click();
cy.get(`#${employee_records.message[3]}`)
.next()
.click();
// siblings of parent should be visible
cy.get('.hierarchy-mobile').prev().as('sibling_group');
cy.get('@sibling_group')
.should('exist')
.should('have.class', 'sibling-group')
.should('not.have.class', 'collapsed');
cy.get(`#${employee_records.message[1]}`)
.should('be.visible')
.should('have.class', 'active');
cy.get(`[data-parent="${employee_records.message[1]}"]`)
.should('be.visible')
.should('have.length', 2)
.should('have.class', 'active-child');
});
});
it('goes to the respective level after clicking on non-collapsed sibling group', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(() => {
// click on non-collapsed sibling group
cy.get('.hierarchy-mobile')
.prev()
.click();
// should take you to that level
cy.get('.hierarchy-mobile').find('li.level .node-card').should('have.length', 2);
});
});
it('edit node navigates to employee master', () => {
cy.call('erpnext.tests.ui_test_helpers.get_employee_records').then(employee_records => {
cy.get(`#${employee_records.message[0]}`).find('.btn-edit-node')
.click();
cy.url().should('include', `/employee/${employee_records.message[0]}`);
});
});
});

17
cypress/plugins/index.js Normal file
View File

@@ -0,0 +1,17 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = () => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};

View File

@@ -0,0 +1,31 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... });
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... });
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... });
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... });
const slug = (name) => name.toLowerCase().replace(" ", "-");
Cypress.Commands.add("go_to_doc", (doctype, name) => {
cy.visit(`/app/${slug(doctype)}/${encodeURIComponent(name)}`);
});

26
cypress/support/index.js Normal file
View File

@@ -0,0 +1,26 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
import '../../../frappe/cypress/support/commands' // eslint-disable-line
// Alternatively you can use CommonJS syntax:
// require('./commands')
Cypress.Cookies.defaults({
preserve: 'sid'
});

12
cypress/tsconfig.json Normal file
View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "../node_modules",
"types": [
"cypress"
]
},
"include": [
"**/*.*"
]
}

View File

@@ -33,6 +33,8 @@ def get_shipping_address(company, address = None):
if address and frappe.db.get_value('Dynamic Link',
{'parent': address, 'link_name': company}):
filters.append(["Address", "name", "=", address])
if not address:
filters.append(["Address", "is_shipping_address", "=", 1])
address = frappe.get_all("Address", filters=filters, fields=fields) or {}

View File

@@ -263,6 +263,9 @@ def book_deferred_income_or_expense(doc, deferred_process, posting_date=None):
amount, base_amount = calculate_amount(doc, item, last_gl_entry,
total_days, total_booking_days, account_currency)
if not amount:
return
if via_journal_entry:
book_revenue_via_journal_entry(doc, credit_account, debit_account, against, amount,
base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process, submit_journal_entry)
@@ -298,17 +301,21 @@ def process_deferred_accounting(posting_date=None):
start_date = add_months(today(), -1)
end_date = add_days(today(), -1)
for record_type in ('Income', 'Expense'):
doc = frappe.get_doc(dict(
doctype='Process Deferred Accounting',
posting_date=posting_date,
start_date=start_date,
end_date=end_date,
type=record_type
))
companies = frappe.get_all('Company')
doc.insert()
doc.submit()
for company in companies:
for record_type in ('Income', 'Expense'):
doc = frappe.get_doc(dict(
doctype='Process Deferred Accounting',
company=company.name,
posting_date=posting_date,
start_date=start_date,
end_date=end_date,
type=record_type
))
doc.insert()
doc.submit()
def make_gl_entries(doc, credit_account, debit_account, against,
amount, base_amount, posting_date, project, account_currency, cost_center, item, deferred_process=None):

View File

@@ -230,7 +230,7 @@ class Account(NestedSet):
if self.check_gle_exists():
throw(_("Account with existing transaction can not be converted to group."))
elif self.account_type and not self.flags.exclude_account_type_check:
throw(_("Cannot covert to Group because Account Type is selected."))
throw(_("Cannot convert to Group because Account Type is selected."))
else:
self.is_group = 1
self.save()

View File

@@ -19,7 +19,7 @@ class AccountingDimension(Document):
def validate(self):
if self.document_type in core_doctypes_list + ('Accounting Dimension', 'Project',
'Cost Center', 'Accounting Dimension Detail', 'Company') :
'Cost Center', 'Accounting Dimension Detail', 'Company', 'Account') :
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)

View File

@@ -19,6 +19,7 @@
"book_asset_depreciation_entry_automatically",
"unlink_advance_payment_on_cancelation_of_order",
"post_change_gl_entries",
"enable_discount_accounting",
"tax_settings_section",
"determine_address_tax_category_from",
"column_break_19",
@@ -257,9 +258,17 @@
},
{
"default": "1",
"description": "If enabled, ledger entries will be posted for change amount in POS transactions",
"fieldname": "post_change_gl_entries",
"fieldtype": "Check",
"label": "Post Ledger Entries for Given Change"
"label": "Create Ledger Entries for Change Amount"
},
{
"default": "0",
"description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account",
"fieldname": "enable_discount_accounting",
"fieldtype": "Check",
"label": "Enable Discount Accounting"
}
],
"icon": "icon-cog",
@@ -267,7 +276,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-05-25 12:34:05.858669",
"modified": "2021-07-12 18:54:29.084958",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -21,6 +21,7 @@ class AccountsSettings(Document):
self.validate_stale_days()
self.enable_payment_schedule_in_print()
self.toggle_discount_accounting_fields()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
@@ -33,3 +34,22 @@ class AccountsSettings(Document):
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check", validate_fields_for_doctype=False)
make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check", validate_fields_for_doctype=False)
def toggle_discount_accounting_fields(self):
enable_discount_accounting = cint(self.enable_discount_accounting)
for doctype in ["Sales Invoice Item", "Purchase Invoice Item"]:
make_property_setter(doctype, "discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
if enable_discount_accounting:
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
else:
make_property_setter(doctype, "discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
for doctype in ["Sales Invoice", "Purchase Invoice"]:
make_property_setter(doctype, "additional_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)
if enable_discount_accounting:
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "eval: doc.discount_amount", "Code", validate_fields_for_doctype=False)
else:
make_property_setter(doctype, "additional_discount_account", "mandatory_depends_on", "", "Code", validate_fields_for_doctype=False)
make_property_setter("Item", "default_discount_account", "hidden", not(enable_discount_accounting), "Check", validate_fields_for_doctype=False)

View File

@@ -51,7 +51,7 @@ class BankStatementImport(DataImport):
self.import_file, self.google_sheets_url
)
if 'Bank Account' not in json.dumps(preview):
if 'Bank Account' not in json.dumps(preview['columns']):
frappe.throw(_("Please add the Bank Account column"))
from frappe.core.page.background_jobs.background_jobs import get_info

View File

@@ -249,7 +249,7 @@ class TestBudget(unittest.TestCase):
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
if budget_against_field == "project":
budget_against = "_Test Project"
budget_against = frappe.db.get_value("Project", {"project_name": "_Test Project"})
else:
budget_against = budget_against_CC or "_Test Cost Center - _TC"
@@ -275,7 +275,7 @@ def set_total_expense_zero(posting_date, budget_against_field=None, budget_again
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
elif budget_against_field == "project":
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project=budget_against, posting_date=nowdate())
def make_budget(**args):
args = frappe._dict(args)

View File

@@ -54,7 +54,7 @@ class CForm(Document):
frappe.throw(_("Please enter atleast 1 invoice in the table"))
def set_total_invoiced_amount(self):
total = sum([flt(d.grand_total) for d in self.get('invoices')])
total = sum(flt(d.grand_total) for d in self.get('invoices'))
frappe.db.set(self, 'total_invoiced_amount', total)
@frappe.whitelist()

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:18:25.410476",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"campaign"
],
"fields": [
{
"fieldname": "campaign",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Campaign",
"options": "Campaign"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:43:49.717633",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Campaign Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 CampaignItem(Document):
pass

View File

@@ -13,7 +13,8 @@ from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import
from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file, read_xls_file_from_attached_file
class ChartofAccountsImporter(Document):
pass
def validate(self):
validate_accounts(self.import_file)
@frappe.whitelist()
def validate_company(company):
@@ -301,28 +302,27 @@ def validate_accounts(file_name):
if account["parent_account"] and accounts_dict.get(account["parent_account"]):
accounts_dict[account["parent_account"]]["is_group"] = 1
message = validate_root(accounts_dict)
if message: return message
message = validate_account_types(accounts_dict)
if message: return message
validate_root(accounts_dict)
validate_account_types(accounts_dict)
return [True, len(accounts)]
def validate_root(accounts):
roots = [accounts[d] for d in accounts if not accounts[d].get('parent_account')]
if len(roots) < 4:
return _("Number of root accounts cannot be less than 4")
frappe.throw(_("Number of root accounts cannot be less than 4"))
error_messages = []
for account in roots:
if not account.get("root_type") and account.get("account_name"):
error_messages.append("Please enter Root Type for account- {0}".format(account.get("account_name")))
error_messages.append(_("Please enter Root Type for account- {0}").format(account.get("account_name")))
elif account.get("root_type") not in get_root_types() and account.get("account_name"):
error_messages.append("Root Type for {0} must be one of the Asset, Liability, Income, Expense and Equity".format(account.get("account_name")))
error_messages.append(_("Root Type for {0} must be one of the Asset, Liability, Income, Expense and Equity").format(account.get("account_name")))
if error_messages:
return "<br>".join(error_messages)
frappe.throw("<br>".join(error_messages))
def get_root_types():
return ('Asset', 'Liability', 'Expense', 'Income', 'Equity')
@@ -356,7 +356,7 @@ def validate_account_types(accounts):
missing = list(set(account_types_for_ledger) - set(account_types))
if missing:
return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))
frappe.throw(_("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing)))
account_types_for_group = ["Bank", "Cash", "Stock"]
# fix logic bug
@@ -364,7 +364,7 @@ def validate_account_types(accounts):
missing = list(set(account_types_for_group) - set(account_groups))
if missing:
return _("Please identify/create Account (Group) for type - {0}").format(' , '.join(missing))
frappe.throw(_("Please identify/create Account (Group) for type - {0}").format(' , '.join(missing)))
def unset_existing_data(company):
linked = frappe.db.sql('''select fieldname from tabDocField
@@ -391,5 +391,5 @@ def set_default_accounts(company):
})
company.save()
install_country_fixtures(company.name)
install_country_fixtures(company.name, company.country)
company.create_default_tax_template()

View File

@@ -14,7 +14,7 @@ class CouponCode(Document):
if not self.coupon_code:
if self.coupon_type == "Promotional":
self.coupon_code =''.join([i for i in self.coupon_name if not i.isdigit()])[0:8].upper()
self.coupon_code =''.join(i for i in self.coupon_name if not i.isdigit())[0:8].upper()
elif self.coupon_type == "Gift Card":
self.coupon_code = frappe.generate_hash()[:10].upper()

View File

@@ -57,7 +57,7 @@ def test_create_test_data():
})
item_price.insert()
# create test item pricing rule
if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
if not frappe.db.exists("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}):
item_pricing_rule = frappe.get_doc({
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule for _Test Item",
@@ -86,14 +86,15 @@ def test_create_test_data():
sales_partner.insert()
# create test item coupon code
if not frappe.db.exists("Coupon Code", "SAVE30"):
pricing_rule = frappe.db.get_value("Pricing Rule", {"title": "_Test Pricing Rule for _Test Item"}, ['name'])
coupon_code = frappe.get_doc({
"doctype": "Coupon Code",
"coupon_name":"SAVE30",
"coupon_code":"SAVE30",
"pricing_rule": "_Test Pricing Rule for _Test Item",
"valid_from": "2014-01-01",
"maximum_use":1,
"used":0
"doctype": "Coupon Code",
"coupon_name":"SAVE30",
"coupon_code":"SAVE30",
"pricing_rule": pricing_rule,
"valid_from": "2014-01-01",
"maximum_use":1,
"used":0
})
coupon_code.insert()
@@ -102,7 +103,7 @@ class TestCouponCode(unittest.TestCase):
test_create_test_data()
def tearDown(self):
frappe.set_user("Administrator")
frappe.set_user("Administrator")
def test_sales_order_with_coupon_code(self):
frappe.db.set_value("Coupon Code", "SAVE30", "used", 0)

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:12:42.558878",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"customer_group"
],
"fields": [
{
"fieldname": "customer_group",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Customer Group",
"options": "Customer Group"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:39:21.563506",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Customer Group Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 CustomerGroupItem(Document):
pass

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-05 14:04:54.266353",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"customer"
],
"fields": [
{
"fieldname": "customer",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Customer ",
"options": "Customer"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-06 10:02:32.967841",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Customer Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 CustomerItem(Document):
pass

View File

@@ -25,7 +25,7 @@ class Dunning(AccountsController):
def validate_amount(self):
amounts = calculate_interest_and_amount(
self.posting_date, self.outstanding_amount, self.rate_of_interest, self.dunning_fee, self.overdue_days)
self.outstanding_amount, self.rate_of_interest, self.dunning_fee, self.overdue_days)
if self.interest_amount != amounts.get('interest_amount'):
self.interest_amount = flt(amounts.get('interest_amount'), self.precision('interest_amount'))
if self.dunning_amount != amounts.get('dunning_amount'):
@@ -86,18 +86,18 @@ def resolve_dunning(doc, state):
for reference in doc.references:
if reference.reference_doctype == 'Sales Invoice' and reference.outstanding_amount <= 0:
dunnings = frappe.get_list('Dunning', filters={
'sales_invoice': reference.reference_name, 'status': ('!=', 'Resolved')})
'sales_invoice': reference.reference_name, 'status': ('!=', 'Resolved')}, ignore_permissions=True)
for dunning in dunnings:
frappe.db.set_value("Dunning", dunning.name, "status", 'Resolved')
def calculate_interest_and_amount(posting_date, outstanding_amount, rate_of_interest, dunning_fee, overdue_days):
def calculate_interest_and_amount(outstanding_amount, rate_of_interest, dunning_fee, overdue_days):
interest_amount = 0
grand_total = 0
grand_total = flt(outstanding_amount) + flt(dunning_fee)
if rate_of_interest:
interest_per_year = flt(outstanding_amount) * flt(rate_of_interest) / 100
interest_amount = (interest_per_year * cint(overdue_days)) / 365
grand_total = flt(outstanding_amount) + flt(interest_amount) + flt(dunning_fee)
interest_amount = (interest_per_year * cint(overdue_days)) / 365
grand_total += flt(interest_amount)
dunning_amount = flt(interest_amount) + flt(dunning_fee)
return {
'interest_amount': interest_amount,

View File

@@ -16,6 +16,7 @@ class TestDunning(unittest.TestCase):
@classmethod
def setUpClass(self):
create_dunning_type()
create_dunning_type_with_zero_interest_rate()
unlink_payment_on_cancel_of_invoice()
@classmethod
@@ -25,11 +26,20 @@ class TestDunning(unittest.TestCase):
def test_dunning(self):
dunning = create_dunning()
amounts = calculate_interest_and_amount(
dunning.posting_date, dunning.outstanding_amount, dunning.rate_of_interest, dunning.dunning_fee, dunning.overdue_days)
dunning.outstanding_amount, dunning.rate_of_interest, dunning.dunning_fee, dunning.overdue_days)
self.assertEqual(round(amounts.get('interest_amount'), 2), 0.44)
self.assertEqual(round(amounts.get('dunning_amount'), 2), 20.44)
self.assertEqual(round(amounts.get('grand_total'), 2), 120.44)
def test_dunning_with_zero_interest_rate(self):
dunning = create_dunning_with_zero_interest_rate()
amounts = calculate_interest_and_amount(
dunning.outstanding_amount, dunning.rate_of_interest, dunning.dunning_fee, dunning.overdue_days)
self.assertEqual(round(amounts.get('interest_amount'), 2), 0)
self.assertEqual(round(amounts.get('dunning_amount'), 2), 20)
self.assertEqual(round(amounts.get('grand_total'), 2), 120)
def test_gl_entries(self):
dunning = create_dunning()
dunning.submit()
@@ -83,6 +93,27 @@ def create_dunning():
dunning.save()
return dunning
def create_dunning_with_zero_interest_rate():
posting_date = add_days(today(), -20)
due_date = add_days(today(), -15)
sales_invoice = create_sales_invoice_against_cost_center(
posting_date=posting_date, due_date=due_date, status='Overdue')
dunning_type = frappe.get_doc("Dunning Type", 'First Notice with 0% Rate of Interest')
dunning = frappe.new_doc("Dunning")
dunning.sales_invoice = sales_invoice.name
dunning.customer_name = sales_invoice.customer_name
dunning.outstanding_amount = sales_invoice.outstanding_amount
dunning.debit_to = sales_invoice.debit_to
dunning.currency = sales_invoice.currency
dunning.company = sales_invoice.company
dunning.posting_date = nowdate()
dunning.due_date = sales_invoice.due_date
dunning.dunning_type = 'First Notice with 0% Rate of Interest'
dunning.rate_of_interest = dunning_type.rate_of_interest
dunning.dunning_fee = dunning_type.dunning_fee
dunning.save()
return dunning
def create_dunning_type():
dunning_type = frappe.new_doc("Dunning Type")
dunning_type.dunning_type = 'First Notice'
@@ -98,3 +129,19 @@ def create_dunning_type():
}
)
dunning_type.save()
def create_dunning_type_with_zero_interest_rate():
dunning_type = frappe.new_doc("Dunning Type")
dunning_type.dunning_type = 'First Notice with 0% Rate of Interest'
dunning_type.start_day = 10
dunning_type.end_day = 20
dunning_type.dunning_fee = 20
dunning_type.rate_of_interest = 0
dunning_type.append(
"dunning_letter_text", {
'language': 'en',
'body_text': 'We have still not received payment for our invoice ',
'closing_text': 'We kindly request that you pay the outstanding amount immediately, and late fees.'
}
)
dunning_type.save()

View File

@@ -27,6 +27,9 @@ class ExchangeRateRevaluation(Document):
if not (self.company and self.posting_date):
frappe.throw(_("Please select Company and Posting Date to getting entries"))
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry')
@frappe.whitelist()
def check_journal_entry_condition(self):
total_debit = frappe.db.get_value("Journal Entry Account", {
@@ -99,10 +102,12 @@ class ExchangeRateRevaluation(Document):
sum(debit) - sum(credit) as balance
from `tabGL Entry`
where account in (%s)
group by account, party_type, party
and posting_date <= %s
and is_cancelled = 0
group by account, NULLIF(party_type,''), NULLIF(party,'')
having sum(debit) != sum(credit)
order by account
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
""" % (', '.join(['%s']*len(accounts)), '%s'), tuple(accounts + [self.posting_date]), as_dict=1)
return account_details
@@ -143,9 +148,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate":d.get("new_exchange_rate"),
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
"exchange_rate": flt(d.get("new_exchange_rate"), d.precision("new_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
})
@@ -154,9 +159,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
reverse_dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate": d.get("current_exchange_rate"),
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
reverse_dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
"exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name
})
@@ -185,9 +190,9 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
account_details = {}
company_currency = erpnext.get_company_currency(company)
balance = get_balance_on(account, party_type=party_type, party=party, in_account_currency=False)
balance = get_balance_on(account, date=posting_date, party_type=party_type, party=party, in_account_currency=False)
if balance:
balance_in_account_currency = get_balance_on(account, party_type=party_type, party=party)
balance_in_account_currency = get_balance_on(account, date=posting_date, party_type=party_type, party=party)
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate

View File

@@ -58,8 +58,8 @@ class GLEntry(Document):
if not self.get(k):
frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
account_type = frappe.get_cached_value("Account", self.account, "account_type")
if not (self.party_type and self.party):
account_type = frappe.get_cached_value("Account", self.account, "account_type")
if account_type == "Receivable":
frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
.format(self.voucher_type, self.voucher_no, self.account))
@@ -73,15 +73,19 @@ class GLEntry(Document):
.format(self.voucher_type, self.voucher_no, self.account))
def pl_must_have_cost_center(self):
if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
msg = _("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}.").format(
self.voucher_type, self.voucher_no, self.account)
msg += " "
msg += _("Please set the cost center field in {0} or setup a default Cost Center for the Company.").format(
self.voucher_type)
"""Validate that profit and loss type account GL entries have a cost center."""
frappe.throw(msg, title=_("Missing Cost Center"))
if self.cost_center or self.voucher_type == 'Period Closing Voucher':
return
if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
msg = _("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}.").format(
self.voucher_type, self.voucher_no, self.account)
msg += " "
msg += _("Please set the cost center field in {0} or setup a default Cost Center for the Company.").format(
self.voucher_type)
frappe.throw(msg, title=_("Missing Cost Center"))
def validate_dimensions_for_pl_and_bs(self):
account_type = frappe.db.get_value("Account", self.account, "report_type")
@@ -121,8 +125,7 @@ class GLEntry(Document):
def check_pl_account(self):
if self.is_opening=='Yes' and \
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss" and \
self.voucher_type not in ['Purchase Invoice', 'Sales Invoice']:
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss":
frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry")
.format(self.voucher_type, self.voucher_no, self.account))

View File

@@ -42,7 +42,7 @@ class InvoiceDiscounting(AccountsController):
record.idx, frappe.bold(actual_outstanding), frappe.bold(record.sales_invoice)))
def calculate_total_amount(self):
self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
self.total_amount = sum(flt(d.outstanding_amount) for d in self.invoices)
def on_submit(self):
self.update_sales_invoice()

View File

@@ -196,8 +196,8 @@ class JournalEntry(AccountsController):
frappe.throw(_("Row {0}: Party Type and Party is required for Receivable / Payable account {1}").format(d.idx, d.account))
def check_credit_limit(self):
customers = list(set([d.party for d in self.get("accounts")
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
customers = list(set(d.party for d in self.get("accounts")
if d.party_type=="Customer" and d.party and flt(d.debit) > 0))
if customers:
from erpnext.selling.doctype.customer.customer import check_credit_limit
for customer in customers:

View File

@@ -21,7 +21,7 @@ class MonthlyDistribution(Document):
idx += 1
def validate(self):
total = sum([flt(d.percentage_allocation) for d in self.get("percentages")])
total = sum(flt(d.percentage_allocation) for d in self.get("percentages"))
if flt(total, 2) != 100.0:
frappe.throw(_("Percentage Allocation should be equal to 100%") + \

View File

@@ -7,6 +7,8 @@ cur_frm.cscript.tax_table = "Advance Taxes and Charges";
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice'];
if(frm.doc.__islocal) {
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
@@ -1087,6 +1089,8 @@ frappe.ui.form.on('Payment Entry', {
initialize_taxes: function(frm) {
$.each(frm.doc["taxes"] || [], function(i, tax) {
frm.events.validate_taxes_and_charges(tax);
frm.events.validate_inclusive_tax(tax);
tax.item_wise_tax_detail = {};
let tax_fields = ["total", "tax_fraction_for_current_item",
"grand_total_fraction_for_current_item"];
@@ -1101,6 +1105,73 @@ frappe.ui.form.on('Payment Entry', {
});
},
validate_taxes_and_charges: function(d) {
let msg = "";
if (d.account_head && !d.description) {
// set description from account head
d.description = d.account_head.split(' - ').slice(0, -1).join(' - ');
}
if (!d.charge_type && (d.row_id || d.rate || d.tax_amount)) {
msg = __("Please select Charge Type first");
d.row_id = "";
d.rate = d.tax_amount = 0.0;
} else if ((d.charge_type == 'Actual' || d.charge_type == 'On Net Total' || d.charge_type == 'On Paid Amount') && d.row_id) {
msg = __("Can refer row only if the charge type is 'On Previous Row Amount' or 'Previous Row Total'");
d.row_id = "";
} else if ((d.charge_type == 'On Previous Row Amount' || d.charge_type == 'On Previous Row Total') && d.row_id) {
if (d.idx == 1) {
msg = __("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row");
d.charge_type = '';
} else if (!d.row_id) {
msg = __("Please specify a valid Row ID for row {0} in table {1}", [d.idx, __(d.doctype)]);
d.row_id = "";
} else if (d.row_id && d.row_id >= d.idx) {
msg = __("Cannot refer row number greater than or equal to current row number for this Charge type");
d.row_id = "";
}
}
if (msg) {
frappe.validated = false;
refresh_field("taxes");
frappe.throw(msg);
}
},
validate_inclusive_tax: function(tax) {
let actual_type_error = function() {
let msg = __("Actual type tax cannot be included in Item rate in row {0}", [tax.idx])
frappe.throw(msg);
};
let on_previous_row_error = function(row_range) {
let msg = __("For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included",
[tax.idx, __(tax.doctype), tax.charge_type, row_range])
frappe.throw(msg);
};
if(cint(tax.included_in_paid_amount)) {
if(tax.charge_type == "Actual") {
// inclusive tax cannot be of type Actual
actual_type_error();
} else if(tax.charge_type == "On Previous Row Amount" &&
!cint(this.frm.doc["taxes"][tax.row_id - 1].included_in_paid_amount)
) {
// referred row should also be an inclusive tax
on_previous_row_error(tax.row_id);
} else if(tax.charge_type == "On Previous Row Total") {
let taxes_not_included = $.map(this.frm.doc["taxes"].slice(0, tax.row_id),
function(t) { return cint(t.included_in_paid_amount) ? null : t; });
if(taxes_not_included.length > 0) {
// all rows above this tax should be inclusive
on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
}
}
}
},
determine_exclusive_rate: function(frm) {
let has_inclusive_tax = false;
$.each(frm.doc["taxes"] || [], function(i, row) {
@@ -1110,8 +1181,7 @@ frappe.ui.form.on('Payment Entry', {
let cumulated_tax_fraction = 0.0;
$.each(frm.doc["taxes"] || [], function(i, tax) {
let current_tax_fraction = frm.events.get_current_tax_fraction(frm, tax);
tax.tax_fraction_for_current_item = current_tax_fraction[0];
tax.tax_fraction_for_current_item = frm.events.get_current_tax_fraction(frm, tax);
if(i==0) {
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
@@ -1132,9 +1202,7 @@ frappe.ui.form.on('Payment Entry', {
if(cint(tax.included_in_paid_amount)) {
let tax_rate = tax.rate;
if (tax.charge_type == "Actual") {
current_tax_fraction = tax.tax_amount/(frm.doc.paid_amount_after_tax + frm.doc.tax_amount);
} else if(tax.charge_type == "On Paid Amount") {
if(tax.charge_type == "On Paid Amount") {
current_tax_fraction = (tax_rate / 100.0);
} else if(tax.charge_type == "On Previous Row Amount") {
current_tax_fraction = (tax_rate / 100.0) *
@@ -1147,7 +1215,6 @@ frappe.ui.form.on('Payment Entry', {
if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") {
current_tax_fraction *= -1;
inclusive_tax_amount_per_qty *= -1;
}
return current_tax_fraction;
},
@@ -1207,10 +1274,8 @@ frappe.ui.form.on('Payment Entry', {
frappe.throw(
__("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"));
}
if (!tax.row_id) {
tax.row_id = tax.idx - 1;
}
}
if(tax.charge_type == "Actual") {
current_tax_amount = flt(tax.tax_amount, precision("tax_amount", tax))
} else if(tax.charge_type == "On Paid Amount") {
@@ -1296,6 +1361,11 @@ frappe.ui.form.on('Advance Taxes and Charges', {
included_in_paid_amount: function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
},
charge_type: function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
}
})

View File

@@ -667,6 +667,7 @@
{
"fieldname": "base_paid_amount_after_tax",
"fieldtype": "Currency",
"hidden": 1,
"label": "Paid Amount After Tax (Company Currency)",
"options": "Company:company:default_currency",
"read_only": 1
@@ -690,24 +691,28 @@
"options": "Account"
},
{
"depends_on": "eval:doc.received_amount",
"depends_on": "eval:doc.received_amount && doc.payment_type != 'Internal Transfer'",
"fieldname": "received_amount_after_tax",
"fieldtype": "Currency",
"hidden": 1,
"label": "Received Amount After Tax",
"options": "paid_to_account_currency"
"options": "paid_to_account_currency",
"read_only": 1
},
{
"depends_on": "doc.received_amount",
"fieldname": "base_received_amount_after_tax",
"fieldtype": "Currency",
"hidden": 1,
"label": "Received Amount After Tax (Company Currency)",
"options": "Company:company:default_currency"
"options": "Company:company:default_currency",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-06-09 11:55:04.215050",
"modified": "2021-07-09 08:58:15.008761",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, erpnext, json
from frappe import _, scrub, ValidationError
from frappe import _, scrub, ValidationError, throw
from frappe.utils import flt, comma_or, nowdate, getdate, cint
from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
from erpnext.accounts.party import get_party_account
@@ -16,9 +16,10 @@ from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_ac
from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status
from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from six import string_types, iteritems
from erpnext.controllers.accounts_controller import validate_taxes_and_charges
class InvalidPaymentEntry(ValidationError):
pass
@@ -182,6 +183,13 @@ class PaymentEntry(AccountsController):
d.reference_name, self.party_account_currency)
for field, value in iteritems(ref_details):
if d.exchange_gain_loss:
# for cases where gain/loss is booked into invoice
# exchange_gain_loss is calculated from invoice & populated
# and row.exchange_rate is already set to payment entry's exchange rate
# refer -> `update_reference_in_payment_entry()` in utils.py
continue
if field == 'exchange_rate' or not d.get(field) or force:
d.db_set(field, value)
@@ -309,7 +317,7 @@ class PaymentEntry(AccountsController):
for k, v in no_oustanding_refs.items():
frappe.msgprint(
_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.")
.format(k, frappe.bold(", ".join([d.reference_name for d in v])), frappe.bold("negative outstanding amount"))
.format(k, frappe.bold(", ".join(d.reference_name for d in v)), frappe.bold("negative outstanding amount"))
+ "<br><br>" + _("If this is undesirable please cancel the corresponding Payment Entry."),
title=_("Warning"), indicator="orange")
@@ -403,23 +411,15 @@ class PaymentEntry(AccountsController):
if not self.advance_tax_account:
frappe.throw(_("Advance TDS account is mandatory for advance TDS deduction"))
reference_doclist = []
net_total = self.paid_amount
included_in_paid_amount = 0
if self.get('references'):
for doc in self.get('references'):
if doc.reference_doctype == 'Purchase Order':
reference_doclist.append(doc.reference_name)
if reference_doclist:
order_amount = frappe.db.get_all('Purchase Order', fields=['sum(net_total)'],
filters = {'name': ('in', reference_doclist), 'docstatus': 1,
'apply_tds': 1}, as_list=1)
if order_amount:
net_total = order_amount[0][0]
included_in_paid_amount = 1
for reference in self.get("references"):
net_total_for_tds = 0
if reference.reference_doctype == 'Purchase Order':
net_total_for_tds += flt(frappe.db.get_value('Purchase Order', reference.reference_name, 'net_total'))
if net_total_for_tds:
net_total = net_total_for_tds
# Adding args as purchase invoice to get TDS amount
args = frappe._dict({
@@ -436,7 +436,7 @@ class PaymentEntry(AccountsController):
return
tax_withholding_details.update({
'included_in_paid_amount': included_in_paid_amount,
'add_deduct_tax': 'Add',
'cost_center': self.cost_center or erpnext.get_default_cost_center(self.company)
})
@@ -524,17 +524,20 @@ class PaymentEntry(AccountsController):
def set_unallocated_amount(self):
self.unallocated_amount = 0
if self.party:
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
included_taxes = self.get_included_taxes()
if self.payment_type == "Receive" \
and self.base_total_allocated_amount < self.base_received_amount_after_tax + total_deductions \
and self.total_allocated_amount < self.paid_amount_after_tax + (total_deductions / self.source_exchange_rate):
self.unallocated_amount = (self.received_amount_after_tax + total_deductions -
and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
self.unallocated_amount = (self.received_amount + total_deductions -
self.base_total_allocated_amount) / self.source_exchange_rate
self.unallocated_amount -= included_taxes
elif self.payment_type == "Pay" \
and self.base_total_allocated_amount < (self.base_paid_amount_after_tax - total_deductions) \
and self.total_allocated_amount < self.received_amount_after_tax + (total_deductions / self.target_exchange_rate):
self.unallocated_amount = (self.base_paid_amount_after_tax - (total_deductions +
and self.base_total_allocated_amount < (self.base_paid_amount - total_deductions) \
and self.total_allocated_amount < self.received_amount + (total_deductions / self.target_exchange_rate):
self.unallocated_amount = (self.base_paid_amount - (total_deductions +
self.base_total_allocated_amount)) / self.target_exchange_rate
self.unallocated_amount -= included_taxes
def set_difference_amount(self):
base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate)
@@ -543,17 +546,29 @@ class PaymentEntry(AccountsController):
base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
if self.payment_type == "Receive":
self.difference_amount = base_party_amount - self.base_received_amount_after_tax
self.difference_amount = base_party_amount - self.base_received_amount
elif self.payment_type == "Pay":
self.difference_amount = self.base_paid_amount_after_tax - base_party_amount
self.difference_amount = self.base_paid_amount - base_party_amount
else:
self.difference_amount = self.base_paid_amount_after_tax - flt(self.base_received_amount_after_tax)
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
total_deductions = sum(flt(d.amount) for d in self.get("deductions"))
included_taxes = self.get_included_taxes()
self.difference_amount = flt(self.difference_amount - total_deductions,
self.difference_amount = flt(self.difference_amount - total_deductions - included_taxes,
self.precision("difference_amount"))
def get_included_taxes(self):
included_taxes = 0
for tax in self.get('taxes'):
if tax.included_in_paid_amount:
if tax.add_deduct_tax == 'Add':
included_taxes += tax.base_tax_amount
else:
included_taxes -= tax.base_tax_amount
return included_taxes
# Paid amount is auto allocated in the reference document by default.
# Clear the reference document which doesn't have allocated amount on validate so that form can be loaded fast
def clear_unallocated_reference_document_rows(self):
@@ -565,8 +580,8 @@ class PaymentEntry(AccountsController):
if ((self.payment_type=="Pay" and self.party_type=="Customer")
or (self.payment_type=="Receive" and self.party_type=="Supplier")):
total_negative_outstanding = sum([abs(flt(d.outstanding_amount))
for d in self.get("references") if flt(d.outstanding_amount) < 0])
total_negative_outstanding = sum(abs(flt(d.outstanding_amount))
for d in self.get("references") if flt(d.outstanding_amount) < 0)
paid_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount
additional_charges = sum([flt(d.amount) for d in self.deductions])
@@ -677,8 +692,8 @@ class PaymentEntry(AccountsController):
gl_entries.append(gle)
if self.unallocated_amount:
base_unallocated_amount = self.unallocated_amount * \
(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = (self.unallocated_amount * exchange_rate)
gle = party_gl_dict.copy()
@@ -696,8 +711,8 @@ class PaymentEntry(AccountsController):
"account": self.paid_from,
"account_currency": self.paid_from_account_currency,
"against": self.party if self.payment_type=="Pay" else self.paid_to,
"credit_in_account_currency": self.paid_amount_after_tax,
"credit": self.base_paid_amount_after_tax,
"credit_in_account_currency": self.paid_amount,
"credit": self.base_paid_amount,
"cost_center": self.cost_center
}, item=self)
)
@@ -707,8 +722,8 @@ class PaymentEntry(AccountsController):
"account": self.paid_to,
"account_currency": self.paid_to_account_currency,
"against": self.party if self.payment_type=="Receive" else self.paid_from,
"debit_in_account_currency": self.received_amount_after_tax,
"debit": self.base_received_amount_after_tax,
"debit_in_account_currency": self.received_amount,
"debit": self.base_received_amount,
"cost_center": self.cost_center
}, item=self)
)
@@ -719,35 +734,44 @@ class PaymentEntry(AccountsController):
if account_currency != self.company_currency:
frappe.throw(_("Currency for {0} must be {1}").format(d.account_head, self.company_currency))
if (self.payment_type == 'Pay' and self.advance_tax_account) or self.payment_type == 'Receive':
if self.payment_type in ('Pay', 'Internal Transfer'):
dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
elif (self.payment_type == 'Receive' and self.advance_tax_account) or self.payment_type == 'Pay':
against = self.party or self.paid_from
elif self.payment_type == 'Receive':
dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
against = self.party or self.paid_to
payment_or_advance_account = self.get_party_account_for_taxes()
tax_amount = d.tax_amount
base_tax_amount = d.base_tax_amount
if self.advance_tax_account:
tax_amount = -1 * tax_amount
base_tax_amount = -1 * base_tax_amount
gl_entries.append(
self.get_gl_dict({
"account": d.account_head,
"against": self.party if self.payment_type=="Receive" else self.paid_from,
dr_or_cr: d.base_tax_amount,
dr_or_cr + "_in_account_currency": d.base_tax_amount
"against": against,
dr_or_cr: tax_amount,
dr_or_cr + "_in_account_currency": base_tax_amount
if account_currency==self.company_currency
else d.tax_amount,
"cost_center": d.cost_center
}, account_currency, item=d))
#Intentionally use -1 to get net values in party account
gl_entries.append(
self.get_gl_dict({
"account": payment_or_advance_account,
"against": self.party if self.payment_type=="Receive" else self.paid_from,
dr_or_cr: -1 * d.base_tax_amount,
dr_or_cr + "_in_account_currency": -1*d.base_tax_amount
if account_currency==self.company_currency
else d.tax_amount,
"cost_center": self.cost_center,
}, account_currency, item=d))
if not d.included_in_paid_amount or self.advance_tax_account:
gl_entries.append(
self.get_gl_dict({
"account": payment_or_advance_account,
"against": against,
dr_or_cr: -1 * tax_amount,
dr_or_cr + "_in_account_currency": -1 * base_tax_amount
if account_currency==self.company_currency
else d.tax_amount,
"cost_center": self.cost_center,
}, account_currency, item=d))
def add_deductions_gl_entries(self, gl_entries):
for d in self.get("deductions"):
@@ -770,10 +794,10 @@ class PaymentEntry(AccountsController):
def get_party_account_for_taxes(self):
if self.advance_tax_account:
return self.advance_tax_account
elif self.payment_type == 'Pay':
return self.paid_from
elif self.payment_type == 'Receive':
return self.paid_to
elif self.payment_type in ('Pay', 'Internal Transfer'):
return self.paid_from
def update_advance_paid(self):
if self.payment_type in ("Receive", "Pay") and self.party:
@@ -817,12 +841,22 @@ class PaymentEntry(AccountsController):
if account_details:
row.update(account_details)
if not row.get('amount'):
# if no difference amount
return
self.append('deductions', row)
self.set_unallocated_amount()
def get_exchange_rate(self):
return self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate
def initialize_taxes(self):
for tax in self.get("taxes"):
validate_taxes_and_charges(tax)
validate_inclusive_tax(tax, self)
tax_fields = ["total", "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]
if tax.charge_type != "Actual":
@@ -918,15 +952,11 @@ class PaymentEntry(AccountsController):
if cint(tax.included_in_paid_amount):
tax_rate = tax.rate
if tax.charge_type == 'Actual':
current_tax_fraction = tax.tax_amount/ (self.paid_amount_after_tax + tax.tax_amount)
elif tax.charge_type == "On Paid Amount":
if tax.charge_type == "On Paid Amount":
current_tax_fraction = tax_rate / 100.0
elif tax.charge_type == "On Previous Row Amount":
current_tax_fraction = (tax_rate / 100.0) * \
self.get("taxes")[cint(tax.row_id) - 1].tax_fraction_for_current_item
elif tax.charge_type == "On Previous Row Total":
current_tax_fraction = (tax_rate / 100.0) * \
self.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
@@ -936,6 +966,25 @@ class PaymentEntry(AccountsController):
return current_tax_fraction
def validate_inclusive_tax(tax, doc):
def _on_previous_row_error(row_range):
throw(_("To include tax in row {0} in Item rate, taxes in rows {1} must also be included").format(tax.idx, row_range))
if cint(getattr(tax, "included_in_paid_amount", None)):
if tax.charge_type == "Actual":
# inclusive tax cannot be of type Actual
throw(_("Charge of type 'Actual' in row {0} cannot be included in Item Rate or Paid Amount").format(tax.idx))
elif tax.charge_type == "On Previous Row Amount" and \
not cint(doc.get("taxes")[cint(tax.row_id) - 1].included_in_paid_amount):
# referred row should also be inclusive
_on_previous_row_error(tax.row_id)
elif tax.charge_type == "On Previous Row Total" and \
not all([cint(t.included_in_paid_amount for t in doc.get("taxes")[:cint(tax.row_id) - 1])]):
# all rows about the referred tax should be inclusive
_on_previous_row_error("1 - %d" % (cint(tax.row_id),))
elif tax.get("category") == "Valuation":
frappe.throw(_("Valuation type charges can not be marked as Inclusive"))
@frappe.whitelist()
def get_outstanding_reference_documents(args):
@@ -1311,9 +1360,9 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
return frappe._dict({
"due_date": ref_doc.get("due_date"),
"total_amount": total_amount,
"outstanding_amount": outstanding_amount,
"exchange_rate": exchange_rate,
"total_amount": flt(total_amount),
"outstanding_amount": flt(outstanding_amount),
"exchange_rate": flt(exchange_rate),
"bill_no": bill_no
})
@@ -1626,6 +1675,7 @@ def set_paid_amount_and_received_amount(dt, party_account_currency, bank, outsta
paid_amount = received_amount * doc.get('conversion_rate', 1)
if dt == "Employee Advance":
paid_amount = received_amount * doc.get('exchange_rate', 1)
return paid_amount, received_amount
def apply_early_payment_discount(paid_amount, received_amount, doc):

View File

@@ -589,9 +589,9 @@ class TestPaymentEntry(unittest.TestCase):
party_account_balance = get_balance_on(account=pe.paid_from, cost_center=pe.cost_center)
self.assertEqual(pe.cost_center, si.cost_center)
self.assertEqual(expected_account_balance, account_balance)
self.assertEqual(expected_party_balance, party_balance)
self.assertEqual(expected_party_account_balance, party_account_balance)
self.assertEqual(flt(expected_account_balance), account_balance)
self.assertEqual(flt(expected_party_balance), party_balance)
self.assertEqual(flt(expected_party_account_balance), party_account_balance)
def create_payment_terms_template():

View File

@@ -14,7 +14,8 @@
"total_amount",
"outstanding_amount",
"allocated_amount",
"exchange_rate"
"exchange_rate",
"exchange_gain_loss"
],
"fields": [
{
@@ -90,12 +91,19 @@
"fieldtype": "Link",
"label": "Payment Term",
"options": "Payment Term"
},
{
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
"options": "Company:company:default_currency",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-02-10 11:25:47.144392",
"modified": "2021-04-21 13:30:11.605388",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",

View File

@@ -306,5 +306,5 @@ def reconcile_dr_cr_note(dr_cr_notes, company):
}
]
})
jv.flags.ignore_mandatory = True
jv.submit()

View File

@@ -112,7 +112,7 @@ class PaymentRequest(Document):
if not data_of_completed_requests:
return self.grand_total
request_amounts = sum([json.loads(d).get('request_amount') for d in data_of_completed_requests])
request_amounts = sum(json.loads(d).get('request_amount') for d in data_of_completed_requests)
return request_amounts
def on_cancel(self):

View File

@@ -26,7 +26,7 @@ class PaymentTermsTemplate(Document):
def check_duplicate_terms(self):
terms = []
for term in self.terms:
term_info = (term.credit_days, term.credit_months, term.due_date_based_on)
term_info = (term.payment_term, term.credit_days, term.credit_months, term.due_date_based_on)
if term_info in terms:
frappe.msgprint(
_('The Payment Term at row {0} is possibly a duplicate.').format(term.idx),

View File

@@ -1545,6 +1545,7 @@
"fieldname": "consolidated_invoice",
"fieldtype": "Link",
"label": "Consolidated Sales Invoice",
"no_copy": 1,
"options": "Sales Invoice",
"read_only": 1
}
@@ -1552,7 +1553,7 @@
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2021-02-01 15:03:33.800707",
"modified": "2021-07-29 13:37:20.636171",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",

View File

@@ -2,12 +2,13 @@
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
"autoname": "naming_series:",
"creation": "2014-02-21 15:02:51",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"applicability_section",
"naming_series",
"title",
"disable",
"apply_on",
@@ -95,8 +96,7 @@
"fieldtype": "Data",
"label": "Title",
"no_copy": 1,
"reqd": 1,
"unique": 1
"reqd": 1
},
{
"default": "0",
@@ -558,7 +558,8 @@
"description": "Simple Python Expression, Example: territory != 'All Territories'",
"fieldname": "condition",
"fieldtype": "Code",
"label": "Condition"
"label": "Condition",
"options": "PythonExpression"
},
{
"fieldname": "column_break_42",
@@ -570,12 +571,19 @@
"fieldname": "is_recursive",
"fieldtype": "Check",
"label": "Is Recursive"
},
{
"default": "PRLE-.####",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Naming Series",
"options": "PRLE-.####"
}
],
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2021-03-06 22:01:24.840422",
"modified": "2021-08-06 15:10:04.219321",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
@@ -633,5 +641,6 @@
],
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC"
}
"sort_order": "DESC",
"title_field": "title"
}

View File

@@ -20,9 +20,9 @@ from frappe.utils import cint, flt, get_link_to_form, getdate, today, fmt_money
class MultiplePricingRuleConflict(frappe.ValidationError): pass
apply_on_table = {
'Item Code': 'items',
'Item Group': 'item_groups',
'Brand': 'brands'
'Item Code': 'items',
'Item Group': 'item_groups',
'Brand': 'brands'
}
def get_pricing_rules(args, doc=None):
@@ -168,7 +168,7 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
frappe.throw(_("Invalid {0}").format(args.get(field)))
parent_groups = frappe.db.sql_list("""select name from `tab%s`
where lft>=%s and rgt<=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
if parenttype in ["Customer Group", "Item Group", "Territory"]:
parent_field = "parent_{0}".format(frappe.scrub(parenttype))
@@ -183,7 +183,7 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
table=table,
field=field,
parent_groups=", ".join([frappe.db.escape(d) for d in parent_groups])
parent_groups=", ".join(frappe.db.escape(d) for d in parent_groups)
)
frappe.flags.tree_conditions[key] = condition
@@ -264,7 +264,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
# find pricing rule with highest priority
if pricing_rules:
max_priority = max([cint(p.priority) for p in pricing_rules])
max_priority = max(cint(p.priority) for p in pricing_rules)
if max_priority:
pricing_rules = list(filter(lambda x: cint(x.priority)==max_priority, pricing_rules))
@@ -272,14 +272,14 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
pricing_rules = list(pricing_rules)
if len(pricing_rules) > 1:
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
rate_or_discount = list(set(d.rate_or_discount for d in pricing_rules))
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
or pricing_rules
if len(pricing_rules) > 1 and not args.for_shopping_cart:
frappe.throw(_("Multiple Price Rules exists with same criteria, please resolve conflict by assigning priority. Price Rules: {0}")
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
.format("\n".join(d.name for d in pricing_rules)), MultiplePricingRuleConflict)
elif pricing_rules:
return pricing_rules[0]
@@ -541,7 +541,7 @@ def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
if pricing_rule_args:
items = tuple([(d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item])
items = tuple((d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item)
for args in pricing_rule_args:
if not items or (args.get('item_code'), args.get('pricing_rules')) not in items:
@@ -589,4 +589,4 @@ def update_coupon_code_count(coupon_name,transaction_type):
elif transaction_type=='cancelled':
if coupon.used>0:
coupon.used=coupon.used-1
coupon.save(ignore_permissions=True)
coupon.save(ignore_permissions=True)

View File

@@ -207,10 +207,9 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
@frappe.whitelist()
def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=True):
billing_email = frappe.db.sql("""
SELECT c.email_id FROM `tabContact` AS c JOIN `tabDynamic Link` AS l ON c.name=l.parent \
WHERE l.link_doctype='Customer' and l.link_name='""" + customer_name + """' and \
c.is_billing_contact=1 \
order by c.creation desc""")
SELECT c.email_id FROM `tabContact` AS c JOIN `tabDynamic Link` AS l ON c.name=l.parent
WHERE l.link_doctype='Customer' and l.link_name=%s and c.is_billing_contact=1
order by c.creation desc""", customer_name)
if len(billing_email) == 0 or (billing_email[0][0] is None):
if billing_and_primary:

View File

@@ -25,22 +25,31 @@ product_discount_fields = ['free_item', 'free_qty', 'free_item_uom',
class PromotionalScheme(Document):
def validate(self):
if not self.selling and not self.buying:
frappe.throw(_("Either 'Selling' or 'Buying' must be selected"), title=_("Mandatory"))
if not (self.price_discount_slabs
or self.product_discount_slabs):
frappe.throw(_("Price or product discount slabs are required"))
def on_update(self):
data = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': self.name}) or {}
pricing_rules = frappe.get_all(
'Pricing Rule',
fields = ["promotional_scheme_id", "name", "creation"],
filters = {
'promotional_scheme': self.name,
'applicable_for': self.applicable_for
},
order_by = 'creation asc',
) or {}
self.update_pricing_rules(pricing_rules)
self.update_pricing_rules(data)
def update_pricing_rules(self, data):
def update_pricing_rules(self, pricing_rules):
rules = {}
count = 0
for d in data:
rules[d.get('promotional_scheme_id')] = d.get('name')
names = []
for rule in pricing_rules:
names.append(rule.name)
rules[rule.get('promotional_scheme_id')] = names
docs = get_pricing_rules(self, rules)
@@ -57,9 +66,9 @@ class PromotionalScheme(Document):
frappe.msgprint(_("New {0} pricing rules are created").format(count))
def on_trash(self):
for d in frappe.get_all('Pricing Rule',
for rule in frappe.get_all('Pricing Rule',
{'promotional_scheme': self.name}):
frappe.delete_doc('Pricing Rule', d.name)
frappe.delete_doc('Pricing Rule', rule.name)
def get_pricing_rules(doc, rules = {}):
new_doc = []
@@ -73,42 +82,80 @@ def get_pricing_rules(doc, rules = {}):
def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
new_doc = []
args = get_args_for_pricing_rule(doc)
for d in doc.get(child_doc):
applicable_for = frappe.scrub(doc.get('applicable_for'))
for idx, d in enumerate(doc.get(child_doc)):
if d.name in rules:
pr = frappe.get_doc('Pricing Rule', rules.get(d.name))
for applicable_for_value in args.get(applicable_for):
temp_args = args.copy()
docname = frappe.get_all(
'Pricing Rule',
fields = ["promotional_scheme_id", "name", applicable_for],
filters = {
'promotional_scheme_id': d.name,
applicable_for: applicable_for_value
}
)
if docname:
pr = frappe.get_doc('Pricing Rule', docname[0].get('name'))
temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
else:
pr = frappe.new_doc("Pricing Rule")
pr.title = doc.name
temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
new_doc.append(pr)
else:
pr = frappe.new_doc("Pricing Rule")
pr.title = make_autoname("{0}/.####".format(doc.name))
pr.update(args)
for field in (other_fields + discount_fields):
pr.set(field, d.get(field))
pr.promotional_scheme_id = d.name
pr.promotional_scheme = doc.name
pr.disable = d.disable if d.disable else doc.disable
pr.price_or_product_discount = ('Price'
if child_doc == 'price_discount_slabs' else 'Product')
for field in ['items', 'item_groups', 'brands']:
if doc.get(field):
pr.set(field, [])
apply_on = frappe.scrub(doc.get('apply_on'))
for d in doc.get(field):
pr.append(field, {
apply_on: d.get(apply_on),
'uom': d.uom
})
new_doc.append(pr)
applicable_for_values = args.get(applicable_for) or []
for applicable_for_value in applicable_for_values:
pr = frappe.new_doc("Pricing Rule")
pr.title = doc.name
temp_args = args.copy()
temp_args[applicable_for] = applicable_for_value
pr = set_args(temp_args, pr, doc, child_doc, discount_fields, d)
new_doc.append(pr)
return new_doc
def set_args(args, pr, doc, child_doc, discount_fields, child_doc_fields):
pr.update(args)
for field in (other_fields + discount_fields):
pr.set(field, child_doc_fields.get(field))
pr.promotional_scheme_id = child_doc_fields.name
pr.promotional_scheme = doc.name
pr.disable = child_doc_fields.disable if child_doc_fields.disable else doc.disable
pr.price_or_product_discount = ('Price'
if child_doc == 'price_discount_slabs' else 'Product')
for field in ['items', 'item_groups', 'brands']:
if doc.get(field):
pr.set(field, [])
apply_on = frappe.scrub(doc.get('apply_on'))
for d in doc.get(field):
pr.append(field, {
apply_on: d.get(apply_on),
'uom': d.uom
})
return pr
def get_args_for_pricing_rule(doc):
args = { 'promotional_scheme': doc.name }
applicable_for = frappe.scrub(doc.get('applicable_for'))
for d in pricing_rule_fields:
args[d] = doc.get(d)
if d == applicable_for:
items = []
for applicable_for_values in doc.get(applicable_for):
items.append(applicable_for_values.get(applicable_for))
args[d] = items
else:
args[d] = doc.get(d)
return args

View File

@@ -7,4 +7,54 @@ import frappe
import unittest
class TestPromotionalScheme(unittest.TestCase):
pass
def test_promotional_scheme(self):
ps = make_promotional_scheme()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name", "creation"],
filters = {'promotional_scheme': ps.name})
self.assertTrue(len(price_rules),1)
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer')
self.assertTrue(price_doc_details.min_qty, 4)
self.assertTrue(price_doc_details.discount_percentage, 20)
ps.price_discount_slabs[0].min_qty = 6
ps.append('customer', {
'customer': "_Test Customer 2"})
ps.save()
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
self.assertTrue(len(price_rules), 2)
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[1].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer 2')
self.assertTrue(price_doc_details.min_qty, 6)
self.assertTrue(price_doc_details.discount_percentage, 20)
price_doc_details = frappe.db.get_value('Pricing Rule', price_rules[0].name, ['customer', 'min_qty', 'discount_percentage'], as_dict = 1)
self.assertTrue(price_doc_details.customer, '_Test Customer')
self.assertTrue(price_doc_details.min_qty, 6)
frappe.delete_doc('Promotional Scheme', ps.name)
price_rules = frappe.get_all('Pricing Rule', fields = ["promotional_scheme_id", "name"],
filters = {'promotional_scheme': ps.name})
self.assertEqual(price_rules, [])
def make_promotional_scheme():
ps = frappe.new_doc('Promotional Scheme')
ps.name = '_Test Scheme'
ps.append('items',{
'item_code': '_Test Item'
})
ps.selling = 1
ps.append('price_discount_slabs',{
'min_qty': 4,
'discount_percentage': 20,
'rule_description': 'Test'
})
ps.applicable_for = 'Customer'
ps.append('customer',{
'customer': "_Test Customer"
})
ps.save()
return ps

View File

@@ -27,10 +27,6 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
});
},
company: function() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
},
onload: function() {
this._super();
@@ -138,7 +134,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
},
get_query_filters: {
docstatus: 1,
status: ["not in", ["Closed", "Completed"]],
status: ["not in", ["Closed", "Completed", "Return Issued"]],
company: me.frm.doc.company,
is_return: 0
}
@@ -279,7 +275,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
// Do not update if inter company reference is there as the details will already be updated
if(this.frm.updating_party_details || this.frm.doc.inter_company_invoice_reference)
return;
erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details",
{
posting_date: this.frm.doc.posting_date,
@@ -287,7 +283,8 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
party: this.frm.doc.supplier,
party_type: "Supplier",
account: this.frm.doc.credit_to,
price_list: this.frm.doc.buying_price_list
price_list: this.frm.doc.buying_price_list,
fetch_payment_terms_template: cint(!this.frm.doc.ignore_default_payment_terms_template)
}, function() {
me.apply_pricing_rule();
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
@@ -369,7 +366,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row,
["expense_account", "cost_center", "project"]);
["expense_account", "discount_account", "cost_center", "project"]);
},
on_submit: function() {
@@ -503,6 +500,16 @@ frappe.ui.form.on("Purchase Invoice", {
'Payment Entry': 'Payment'
}
frm.set_query("additional_discount_account", function() {
return {
filters: {
company: frm.doc.company,
is_group: 0,
report_type: "Profit and Loss",
}
};
});
frm.fields_dict['items'].grid.get_field('deferred_expense_account').get_query = function(doc) {
return {
filters: {
@@ -512,6 +519,16 @@ frappe.ui.form.on("Purchase Invoice", {
}
}
}
frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}
},
refresh: function(frm) {
@@ -569,5 +586,9 @@ frappe.ui.form.on("Purchase Invoice", {
frm: frm,
freeze_message: __("Creating Purchase Receipt ...")
})
}
},
company: function(frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
})

View File

@@ -96,6 +96,7 @@
"section_break_44",
"apply_discount_on",
"base_discount_amount",
"additional_discount_account",
"column_break_46",
"additional_discount_percentage",
"discount_amount",
@@ -131,6 +132,7 @@
"advances",
"payment_schedule_section",
"payment_terms_template",
"ignore_default_payment_terms_template",
"payment_schedule",
"terms_section_break",
"tc_name",
@@ -706,11 +708,12 @@
"show_seconds": 1
},
{
"depends_on": "update_stock",
"fieldname": "supplied_items",
"fieldtype": "Table",
"label": "Supplied Items",
"no_copy": 1,
"options": "Purchase Receipt Item Supplied",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
},
@@ -1630,7 +1633,9 @@
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
"options": "Project",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.is_internal_supplier",
@@ -1676,6 +1681,8 @@
"options": "Warehouse",
"print_hide": 1,
"print_width": "50px",
"show_days": 1,
"show_seconds": 1,
"width": "50px"
},
{
@@ -1686,13 +1693,29 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "additional_discount_account",
"fieldtype": "Link",
"label": "Additional Discount Account",
"options": "Account"
},
{
"default": "0",
"fieldname": "ignore_default_payment_terms_template",
"fieldtype": "Check",
"hidden": 1,
"label": "Ignore Default Payment Terms Template",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
}
],
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
"links": [],
"modified": "2021-06-09 12:30:25.632109",
"modified": "2021-08-07 17:53:14.351439",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -22,7 +22,7 @@ from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accoun
from frappe.model.mapper import get_mapped_doc
from six import iteritems
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
unlink_inter_company_doc
unlink_inter_company_doc, check_if_return_invoice_linked_with_payment_entry
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
@@ -400,6 +400,7 @@ class PurchaseInvoice(BuyingController):
# because updating ordered qty in bin depends upon updated ordered qty in PO
if self.update_stock == 1:
self.update_stock_ledger()
self.set_consumed_qty_in_po()
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
update_serial_nos_after_submit(self, "items")
@@ -445,11 +446,13 @@ class PurchaseInvoice(BuyingController):
self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
self.make_discount_gl_entries(gl_entries)
if self.check_asset_cwip_enabled():
self.get_asset_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
self.make_exchange_gain_loss_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries)
self.allocate_advance_taxes(gl_entries)
@@ -516,6 +519,8 @@ class PurchaseInvoice(BuyingController):
if d.category in ('Valuation', 'Total and Valuation')
and flt(d.base_tax_amount_after_discount_amount)]
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
@@ -606,7 +611,7 @@ class PurchaseInvoice(BuyingController):
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
if not item.is_fixed_asset:
amount = flt(item.base_net_amount, item.precision("base_net_amount"))
dummy, amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
else:
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
@@ -820,8 +825,11 @@ class PurchaseInvoice(BuyingController):
def make_tax_gl_entries(self, gl_entries):
# tax table gl entries
valuation_tax = {}
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for tax in self.get("taxes"):
if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
account_currency = get_account_currency(tax.account_head)
dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
@@ -830,21 +838,21 @@ class PurchaseInvoice(BuyingController):
self.get_gl_dict({
"account": tax.account_head,
"against": self.supplier,
dr_or_cr: tax.base_tax_amount_after_discount_amount,
dr_or_cr + "_in_account_currency": tax.base_tax_amount_after_discount_amount \
if account_currency==self.company_currency \
else tax.tax_amount_after_discount_amount,
dr_or_cr: base_amount,
dr_or_cr + "_in_account_currency": base_amount
if account_currency==self.company_currency
else amount,
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
# accumulate valuation tax
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount) \
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(base_amount) \
and not self.is_internal_transfer():
if self.auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
valuation_tax.setdefault(tax.name, 0)
valuation_tax[tax.name] += \
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(base_amount)
if self.is_opening == "No" and self.negative_expense_to_be_booked and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation"
@@ -980,6 +988,8 @@ class PurchaseInvoice(BuyingController):
}, item=self))
def on_cancel(self):
check_if_return_invoice_linked_with_payment_entry(self)
super(PurchaseInvoice, self).on_cancel()
self.check_on_hold_or_closed_status()
@@ -998,6 +1008,7 @@ class PurchaseInvoice(BuyingController):
if self.update_stock == 1:
self.update_stock_ledger()
self.delete_auto_created_batches()
self.set_consumed_qty_in_po()
self.make_gl_entries_on_cancel()

View File

@@ -230,6 +230,50 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(expected_values[gle.account][1], gle.debit)
self.assertEqual(expected_values[gle.account][2], gle.credit)
def test_purchase_invoice_with_discount_accounting_enabled(self):
enable_discount_accounting()
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
pi = make_purchase_invoice(discount_account=discount_account, rate=45)
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
["Creditors - _TC", 0.0, 225.0, nowdate()],
["Discount Account - _TC", 0.0, 25.0, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
enable_discount_accounting(enable=0)
def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
enable_discount_accounting()
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
pi = make_purchase_invoice(do_not_save=1, parent_cost_center="Main - _TC")
pi.apply_discount_on = "Grand Total"
pi.additional_discount_account = additional_discount_account
pi.additional_discount_percentage = 10
pi.disable_rounded_total = 1
pi.append("taxes", {
"charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"description": "Test",
"rate": 10
})
pi.submit()
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
["_Test Account VAT - _TC", 25.0, 0.0, nowdate()],
["Creditors - _TC", 0.0, 247.5, nowdate()],
["Discount Account - _TC", 0.0, 27.5, nowdate()]
]
check_gl_entries(self, pi.name, expected_gle, nowdate())
def test_purchase_invoice_change_naming_series(self):
pi = frappe.copy_doc(test_records[1])
pi.insert()
@@ -621,8 +665,10 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(actual_qty_0, get_qty_after_transaction())
def test_subcontracting_via_purchase_invoice(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import update_backflush_based_on
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
update_backflush_based_on('BOM')
make_stock_entry(item_code="_Test Item", target="_Test Warehouse 1 - _TC", qty=100, basic_rate=100)
make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse 1 - _TC",
qty=100, basic_rate=100)
@@ -632,7 +678,7 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(len(pi.get("supplied_items")), 2)
rm_supp_cost = sum([d.amount for d in pi.get("supplied_items")])
rm_supp_cost = sum(d.amount for d in pi.get("supplied_items"))
self.assertEqual(flt(pi.get("items")[0].rm_supp_cost, 2), flt(rm_supp_cost, 2))
def test_rejected_serial_no(self):
@@ -951,6 +997,120 @@ class TestPurchaseInvoice(unittest.TestCase):
acc_settings.submit_journal_entriessubmit_journal_entries = 0
acc_settings.save()
def test_gain_loss_with_advance_entry(self):
unlink_enabled = frappe.db.get_value(
"Accounts Settings", "Accounts Settings",
"unlink_payment_on_cancel_of_invoice")
frappe.db.set_value(
"Accounts Settings", "Accounts Settings",
"unlink_payment_on_cancel_of_invoice", 1)
original_account = frappe.db.get_value("Company", "_Test Company", "exchange_gain_loss_account")
frappe.db.set_value("Company", "_Test Company", "exchange_gain_loss_account", "Exchange Gain/Loss - _TC")
pay = frappe.get_doc({
'doctype': 'Payment Entry',
'company': '_Test Company',
'payment_type': 'Pay',
'party_type': 'Supplier',
'party': '_Test Supplier USD',
'paid_to': '_Test Payable USD - _TC',
'paid_from': 'Cash - _TC',
'paid_amount': 70000,
'target_exchange_rate': 70,
'received_amount': 1000,
})
pay.insert()
pay.submit()
pi = make_purchase_invoice(supplier='_Test Supplier USD', currency="USD",
conversion_rate=75, rate=500, do_not_save=1, qty=1)
pi.cost_center = "_Test Cost Center - _TC"
pi.advances = []
pi.append("advances", {
"reference_type": "Payment Entry",
"reference_name": pay.name,
"advance_amount": 1000,
"remarks": pay.remarks,
"allocated_amount": 500,
"ref_exchange_rate": 70
})
pi.save()
pi.submit()
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 37500.0],
["_Test Payable USD - _TC", -35000.0],
["Exchange Gain/Loss - _TC", -2500.0]
]
gl_entries = frappe.db.sql("""
select account, sum(debit - credit) as balance from `tabGL Entry`
where voucher_no=%s
group by account
order by account asc""", (pi.name), as_dict=1)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.balance)
pi_2 = make_purchase_invoice(supplier='_Test Supplier USD', currency="USD",
conversion_rate=73, rate=500, do_not_save=1, qty=1)
pi_2.cost_center = "_Test Cost Center - _TC"
pi_2.advances = []
pi_2.append("advances", {
"reference_type": "Payment Entry",
"reference_name": pay.name,
"advance_amount": 500,
"remarks": pay.remarks,
"allocated_amount": 500,
"ref_exchange_rate": 70
})
pi_2.save()
pi_2.submit()
expected_gle = [
["_Test Account Cost for Goods Sold - _TC", 36500.0],
["_Test Payable USD - _TC", -35000.0],
["Exchange Gain/Loss - _TC", -1500.0]
]
gl_entries = frappe.db.sql("""
select account, sum(debit - credit) as balance from `tabGL Entry`
where voucher_no=%s
group by account order by account asc""", (pi_2.name), as_dict=1)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.balance)
expected_gle = [
["_Test Payable USD - _TC", 70000.0],
["Cash - _TC", -70000.0]
]
gl_entries = frappe.db.sql("""
select account, sum(debit - credit) as balance from `tabGL Entry`
where voucher_no=%s and is_cancelled=0
group by account order by account asc""", (pay.name), as_dict=1)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.balance)
pi.reload()
pi.cancel()
pi_2.reload()
pi_2.cancel()
pay.reload()
pay.cancel()
frappe.db.set_value("Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled)
frappe.db.set_value("Company", "_Test Company", "exchange_gain_loss_account", original_account)
def test_purchase_invoice_advance_taxes(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
@@ -964,7 +1124,7 @@ class TestPurchaseInvoice(unittest.TestCase):
update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate())
# Create Purchase Order with TDS applied
po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000)
po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item')
po.apply_tds = 1
po.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
po.save()
@@ -1000,6 +1160,7 @@ class TestPurchaseInvoice(unittest.TestCase):
# Create Purchase Invoice against Purchase Order
purchase_invoice = get_mapped_purchase_invoice(po.name)
purchase_invoice.allocate_advances_automatically = 1
purchase_invoice.items[0].item_code = '_Test Non Stock Item'
purchase_invoice.items[0].expense_account = '_Test Account Cost for Goods Sold - _TC'
purchase_invoice.save()
purchase_invoice.submit()
@@ -1007,21 +1168,33 @@ class TestPurchaseInvoice(unittest.TestCase):
# Check GLE for Purchase Invoice
# Zero net effect on final TDS Payable on invoice
expected_gle = [
['_Test Account Cost for Goods Sold - _TC', 30000, 0],
['_Test Account Excise Duty - _TC', 0, 3000],
['Creditors - _TC', 0, 27000],
['TDS Payable - _TC', 3000, 3000]
['_Test Account Cost for Goods Sold - _TC', 30000],
['_Test Account Excise Duty - _TC', -3000],
['Creditors - _TC', -27000],
['TDS Payable - _TC', 0]
]
gl_entries = frappe.db.sql("""select account, debit, credit
gl_entries = frappe.db.sql("""select account, sum(debit - credit) as amount
from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s
group by account
order by account asc""", (purchase_invoice.name), as_dict=1)
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_gle[i][0], gle.account)
self.assertEqual(expected_gle[i][1], gle.debit)
self.assertEqual(expected_gle[i][2], gle.credit)
self.assertEqual(expected_gle[i][1], gle.amount)
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
order by posting_date asc, account asc""", (voucher_no, posting_date), as_dict=1)
for i, gle in enumerate(gl_entries):
doc.assertEqual(expected_gle[i][0], gle.account)
doc.assertEqual(expected_gle[i][1], gle.debit)
doc.assertEqual(expected_gle[i][2], gle.credit)
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
def update_tax_witholding_category(company, account, date):
from erpnext.accounts.utils import get_fiscal_year
@@ -1053,6 +1226,11 @@ def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings.unlink_payment_on_cancellation_of_invoice = enable
accounts_settings.save()
def enable_discount_accounting(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.enable_discount_accounting = enable
accounts_settings.save()
def make_purchase_invoice(**args):
pi = frappe.new_doc("Purchase Invoice")
args = frappe._dict(args)
@@ -1075,6 +1253,7 @@ def make_purchase_invoice(**args):
pi.return_against = args.return_against
pi.is_subcontracted = args.is_subcontracted or "No"
pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
pi.cost_center = args.parent_cost_center
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
@@ -1083,7 +1262,10 @@ def make_purchase_invoice(**args):
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,
'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"price_list_rate": args.price_list_rate or 50,
"expense_account": args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"discount_account": args.discount_account or None,
"discount_amount": args.discount_amount or 0,
"conversion_factor": 1.0,
"serial_no": args.serial_no,
"stock_uom": args.uom or "_Test UOM",

View File

@@ -1,235 +1,127 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-03-08 15:36:46",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"actions": [],
"creation": "2013-03-08 15:36:46",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"reference_type",
"reference_name",
"remarks",
"reference_row",
"col_break1",
"advance_amount",
"allocated_amount",
"exchange_gain_loss",
"ref_exchange_rate"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Type",
"length": 0,
"no_copy": 1,
"oldfieldname": "journal_voucher",
"oldfieldtype": "Link",
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "180px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"label": "Reference Type",
"no_copy": 1,
"oldfieldname": "journal_voucher",
"oldfieldtype": "Link",
"options": "DocType",
"print_width": "180px",
"read_only": 1,
"width": "180px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Reference Name",
"length": 0,
"no_copy": 1,
"options": "reference_type",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"columns": 3,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
"no_copy": 1,
"options": "reference_type",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "remarks",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Remarks",
"length": 0,
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 3,
"fieldname": "remarks",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Remarks",
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"print_width": "150px",
"read_only": 1,
"width": "150px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Row",
"length": 0,
"no_copy": 1,
"oldfieldname": "jv_detail_no",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "80px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Row",
"no_copy": 1,
"oldfieldname": "jv_detail_no",
"oldfieldtype": "Date",
"print_hide": 1,
"print_width": "80px",
"read_only": 1,
"width": "80px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "col_break1",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "advance_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Advance Amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 2,
"fieldname": "advance_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Advance Amount",
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_width": "100px",
"read_only": 1,
"width": "100px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Allocated Amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Allocated Amount",
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_width": "100px",
"width": "100px"
},
{
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "ref_exchange_rate",
"fieldtype": "Float",
"label": "Reference Exchange Rate",
"non_negative": 1,
"read_only": 1
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-08-26 02:30:54.407138",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Advance",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_order": "DESC",
"track_seen": 0
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-04-20 16:26:53.820530",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Advance",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -73,6 +73,7 @@
"manufacturer_part_no",
"accounting",
"expense_account",
"discount_account",
"col_break5",
"is_fixed_asset",
"asset_location",
@@ -272,7 +273,7 @@
"fieldname": "rate",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Rate ",
"label": "Rate",
"oldfieldname": "import_rate",
"oldfieldtype": "Currency",
"options": "currency",
@@ -849,12 +850,18 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "discount_account",
"fieldtype": "Link",
"label": "Discount Account",
"options": "Account"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-03-30 09:02:39.256602",
"modified": "2021-07-13 02:04:37.787882",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -218,6 +218,7 @@
},
{
"default": "0",
"depends_on": "eval:['Purchase Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
"description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry",
"fieldname": "included_in_paid_amount",
"fieldtype": "Check",
@@ -227,7 +228,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-06-09 11:48:25.335733",
"modified": "2021-06-14 01:43:50.750455",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",

View File

@@ -347,7 +347,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "cost_center"]);
this.frm.script_manager.copy_from_first_row("items", row, ["income_account", "discount_account", "cost_center"]);
},
set_dynamic_labels: function() {
@@ -447,6 +447,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.frm.refresh_field("outstanding_amount");
this.frm.refresh_field("paid_amount");
this.frm.refresh_field("base_paid_amount");
},
currency() {
this._super();
$.each(cur_frm.doc.timesheets, function(i, d) {
let row = frappe.get_doc(d.doctype, d.name)
set_timesheet_detail_rate(row.doctype, row.name, cur_frm.doc.currency, row.timesheet_detail)
});
calculate_total_billing_amount(cur_frm)
}
});
@@ -510,7 +519,6 @@ cur_frm.set_query("income_account", "items", function(doc) {
}
});
// Cost Center in Details Table
// -----------------------------
cur_frm.fields_dict["items"].grid.get_field("cost_center").get_query = function(doc) {
@@ -592,6 +600,16 @@ frappe.ui.form.on('Sales Invoice', {
};
});
frm.set_query("additional_discount_account", function() {
return {
filters: {
company: frm.doc.company,
is_group: 0,
report_type: "Profit and Loss",
}
};
});
frm.custom_make_buttons = {
'Delivery Note': 'Delivery',
'Sales Invoice': 'Return / Credit Note',
@@ -618,6 +636,17 @@ frappe.ui.form.on('Sales Invoice', {
}
}
// discount account
frm.fields_dict['items'].grid.get_field('discount_account').get_query = function(doc) {
return {
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
"is_group": 0
}
}
}
frm.fields_dict['items'].grid.get_field('deferred_revenue_account').get_query = function(doc) {
return {
filters: {
@@ -826,7 +855,8 @@ frappe.ui.form.on('Sales Invoice', {
'time_sheet': row.parent,
'billing_hours': row.billing_hours,
'billing_amount': flt(row.billing_amount) * flt(exchange_rate),
'timesheet_detail': row.name
'timesheet_detail': row.name,
'project_name': row.project_name
});
frm.refresh_field('timesheets');
calculate_total_billing_amount(frm);
@@ -945,43 +975,34 @@ frappe.ui.form.on('Sales Invoice', {
}
})
frappe.ui.form.on('Sales Invoice Timesheet', {
time_sheet: function(frm, cdt, cdn){
var d = locals[cdt][cdn];
if(d.time_sheet) {
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data",
args: {
'name': d.time_sheet,
'project': frm.doc.project || null
},
callback: function(r, rt) {
if(r.message){
let data = r.message;
frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours);
frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount);
frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail);
calculate_total_billing_amount(frm)
}
}
})
}
}
})
var calculate_total_billing_amount = function(frm) {
var doc = frm.doc;
doc.total_billing_amount = 0.0
if(doc.timesheets) {
if (doc.timesheets) {
$.each(doc.timesheets, function(index, data){
doc.total_billing_amount += data.billing_amount
doc.total_billing_amount += flt(data.billing_amount)
})
}
refresh_field('total_billing_amount')
}
var set_timesheet_detail_rate = function(cdt, cdn, currency, timelog) {
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_detail_rate",
args: {
timelog: timelog,
currency: currency
},
callback: function(r) {
if (!r.exc && r.message) {
frappe.model.set_value(cdt, cdn, 'billing_amount', r.message);
}
}
});
}
var select_loyalty_program = function(frm, loyalty_programs) {
var dialog = new frappe.ui.Dialog({
title: __("Select Loyalty Program"),

File diff suppressed because it is too large Load Diff

View File

@@ -290,6 +290,8 @@ class SalesInvoice(SellingController):
self.update_time_sheet(None)
def on_cancel(self):
check_if_return_invoice_linked_with_payment_entry(self)
super(SalesInvoice, self).on_cancel()
self.check_sales_order_on_hold_or_close("sales_order")
@@ -480,7 +482,7 @@ class SalesInvoice(SellingController):
if not self.pos_profile:
pos_profile = get_pos_profile(self.company) or {}
if not pos_profile:
frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
return
self.pos_profile = pos_profile.get('name')
pos = {}
@@ -840,11 +842,13 @@ class SalesInvoice(SellingController):
self.make_customer_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
self.make_exchange_gain_loss_gl_entries(gl_entries)
self.make_internal_transfer_gl_entries(gl_entries)
self.allocate_advance_taxes(gl_entries)
self.make_item_gl_entries(gl_entries)
self.make_discount_gl_entries(gl_entries)
# merge gl entries before adding pos entries
gl_entries = merge_similar_entries(gl_entries)
@@ -884,18 +888,22 @@ class SalesInvoice(SellingController):
)
def make_tax_gl_entries(self, gl_entries):
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for tax in self.get("taxes"):
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
if flt(tax.base_tax_amount_after_discount_amount):
account_currency = get_account_currency(tax.account_head)
gl_entries.append(
self.get_gl_dict({
"account": tax.account_head,
"against": self.customer,
"credit": flt(tax.base_tax_amount_after_discount_amount,
"credit": flt(base_amount,
tax.precision("tax_amount_after_discount_amount")),
"credit_in_account_currency": (flt(tax.base_tax_amount_after_discount_amount,
"credit_in_account_currency": (flt(base_amount,
tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))),
flt(amount, tax.precision("tax_amount_after_discount_amount"))),
"cost_center": tax.cost_center
}, account_currency, item=tax)
)
@@ -914,6 +922,8 @@ class SalesInvoice(SellingController):
def make_item_gl_entries(self, gl_entries):
# income account gl entries
enable_discount_accounting = cint(frappe.db.get_single_value('Accounts Settings', 'enable_discount_accounting'))
for item in self.get("items"):
if flt(item.base_net_amount, item.precision("base_net_amount")):
if item.is_fixed_asset:
@@ -939,15 +949,17 @@ class SalesInvoice(SellingController):
income_account = (item.income_account
if (not item.enable_deferred_revenue or self.is_return) else item.deferred_revenue_account)
amount, base_amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
account_currency = get_account_currency(income_account)
gl_entries.append(
self.get_gl_dict({
"account": income_account,
"against": self.customer,
"credit": flt(item.base_net_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount"))
"credit": flt(base_amount, item.precision("base_net_amount")),
"credit_in_account_currency": (flt(base_amount, item.precision("base_net_amount"))
if account_currency==self.company_currency
else flt(item.net_amount, item.precision("net_amount"))),
else flt(amount, item.precision("net_amount"))),
"cost_center": item.cost_center,
"project": item.project or self.project
}, account_currency, item=item)
@@ -958,6 +970,12 @@ class SalesInvoice(SellingController):
erpnext.is_perpetual_inventory_enabled(self.company):
gl_entries += super(SalesInvoice, self).get_gl_entries()
def set_asset_status(self, asset):
if self.is_return:
asset.set_status()
else:
asset.set_status("Sold" if self.docstatus==1 else None)
def make_loyalty_point_redemption_gle(self, gl_entries):
if cint(self.redeem_loyalty_points):
gl_entries.append(
@@ -989,7 +1007,7 @@ class SalesInvoice(SellingController):
for payment_mode in self.payments:
if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount:
payment_mode.base_amount -= self.change_amount
payment_mode.base_amount -= flt(self.change_amount)
if payment_mode.amount:
# POS, make payment entries
@@ -1923,3 +1941,41 @@ def create_dunning(source_name, target_doc=None):
}
}, target_doc, set_missing_values)
return doclist
def check_if_return_invoice_linked_with_payment_entry(self):
# If a Return invoice is linked with payment entry along with other invoices,
# the cancellation of the Return causes allocated amount to be greater than paid
if not frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
return
payment_entries = []
if self.is_return and self.return_against:
invoice = self.return_against
else:
invoice = self.name
payment_entries = frappe.db.sql_list("""
SELECT
t1.name
FROM
`tabPayment Entry` t1, `tabPayment Entry Reference` t2
WHERE
t1.name = t2.parent
and t1.docstatus = 1
and t2.reference_name = %s
and t2.allocated_amount < 0
""", invoice)
links_to_pe = []
if payment_entries:
for payment in payment_entries:
payment_entry = frappe.get_doc("Payment Entry", payment)
if len(payment_entry.references) > 1:
links_to_pe.append(payment_entry.name)
if links_to_pe:
payment_entries_link = [get_link_to_form('Payment Entry', name, label=name) for name in links_to_pe]
message = _("Please cancel and amend the Payment Entry")
message += " " + ", ".join(payment_entries_link) + " "
message += _("to unallocate the amount of this Return Invoice before cancelling it.")
frappe.throw(message)

View File

@@ -1908,6 +1908,8 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(data['billLists'][0]['sgstValue'], 5400)
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
self.assertEqual(data['billLists'][0]['actualFromStateCode'],7)
self.assertEqual(data['billLists'][0]['fromStateCode'],27)
def test_einvoice_submission_without_irn(self):
# init
@@ -1937,69 +1939,25 @@ class TestSalesInvoice(unittest.TestCase):
frappe.flags.country = country
def test_einvoice_json(self):
from erpnext.regional.india.e_invoice.utils import make_einvoice
from erpnext.regional.india.e_invoice.utils import make_einvoice, validate_totals
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'
si.items = []
si.append("items", {
"item_code": "_Test Item",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 2000,
"rate": 12,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
})
si.append("items", {
"item_code": "_Test Item 2",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 420,
"rate": 15,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
})
si = get_sales_invoice_for_e_invoice()
si.discount_amount = 100
si.save()
einvoice = make_einvoice(si)
total_item_ass_value = 0
total_item_cgst_value = 0
total_item_sgst_value = 0
total_item_igst_value = 0
total_item_value = 0
for item in einvoice['ItemList']:
total_item_ass_value += item['AssAmt']
total_item_cgst_value += item['CgstAmt']
total_item_sgst_value += item['SgstAmt']
total_item_igst_value += item['IgstAmt']
total_item_value += item['TotItemVal']
self.assertTrue(item['AssAmt'], item['TotAmt'] - item['Discount'])
self.assertTrue(item['TotItemVal'], item['AssAmt'] + item['CgstAmt'] + item['SgstAmt'] + item['IgstAmt'])
value_details = einvoice['ValDtls']
self.assertEqual(einvoice['Version'], '1.1')
self.assertEqual(value_details['AssVal'], total_item_ass_value)
self.assertEqual(value_details['CgstVal'], total_item_cgst_value)
self.assertEqual(value_details['SgstVal'], total_item_sgst_value)
self.assertEqual(value_details['IgstVal'], total_item_igst_value)
calculated_invoice_value = \
value_details['AssVal'] + value_details['CgstVal'] \
+ value_details['SgstVal'] + value_details['IgstVal'] \
+ value_details['OthChrg'] - value_details['Discount']
self.assertTrue(value_details['TotInvVal'] - calculated_invoice_value < 0.1)
self.assertEqual(value_details['TotInvVal'], si.base_grand_total)
self.assertTrue(einvoice['EwbDtls'])
validate_totals(einvoice)
si.apply_discount_on = 'Net Total'
si.save()
einvoice = make_einvoice(si)
validate_totals(einvoice)
[d.set('included_in_print_rate', 1) for d in si.taxes]
si.save()
einvoice = make_einvoice(si)
validate_totals(einvoice)
def test_item_tax_net_range(self):
item = create_item("T Shirt")
@@ -2028,6 +1986,83 @@ class TestSalesInvoice(unittest.TestCase):
sales_invoice.save()
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC")
def test_sales_invoice_with_discount_accounting_enabled(self):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
enable_discount_accounting()
discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
si = create_sales_invoice(discount_account=discount_account, discount_percentage=10, rate=90)
expected_gle = [
["Debtors - _TC", 90.0, 0.0, nowdate()],
["Discount Account - _TC", 10.0, 0.0, nowdate()],
["Sales - _TC", 0.0, 100.0, nowdate()]
]
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
enable_discount_accounting(enable=0)
def test_additional_discount_for_sales_invoice_with_discount_accounting_enabled(self):
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import enable_discount_accounting
enable_discount_accounting()
additional_discount_account = create_account(account_name="Discount Account",
parent_account="Indirect Expenses - _TC", company="_Test Company")
si = create_sales_invoice(parent_cost_center='Main - _TC', do_not_save=1)
si.apply_discount_on = "Grand Total"
si.additional_discount_account = additional_discount_account
si.additional_discount_percentage = 20
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "_Test Account VAT - _TC",
"cost_center": "Main - _TC",
"description": "Test",
"rate": 10
})
si.submit()
expected_gle = [
["_Test Account VAT - _TC", 0.0, 10.0, nowdate()],
["Debtors - _TC", 88, 0.0, nowdate()],
["Discount Account - _TC", 22.0, 0.0, nowdate()],
["Sales - _TC", 0.0, 100.0, nowdate()]
]
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
enable_discount_accounting(enable=0)
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'
si.items = []
si.append("items", {
"item_code": "_Test Item",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 2000,
"rate": 12,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
})
si.append("items", {
"item_code": "_Test Item 2",
"uom": "Nos",
"warehouse": "_Test Warehouse - _TC",
"qty": 420,
"rate": 15,
"income_account": "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC",
})
return si
def make_test_address_for_ewaybill():
if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'):
address = frappe.get_doc({
@@ -2077,6 +2112,30 @@ def make_test_address_for_ewaybill():
address.save()
if not frappe.db.exists('Address', '_Test Dispatch-Address for Eway bill-Shipping'):
address = frappe.get_doc({
"address_line1": "_Test Dispatch Address Line 1",
"address_title": "_Test Dispatch-Address for Eway bill",
"address_type": "Shipping",
"city": "_Test City",
"state": "Test State",
"country": "India",
"doctype": "Address",
"is_primary_address": 0,
"phone": "+910000000000",
"gstin": "07AAACC1206D1ZI",
"gst_state": "Delhi",
"gst_state_number": "07",
"pincode": "1100101"
}).insert()
address.append("links", {
"link_doctype": "Company",
"link_name": "_Test Company"
})
address.save()
def make_test_transporter_for_ewaybill():
if not frappe.db.exists('Supplier', '_Test Transporter'):
frappe.get_doc({
@@ -2103,9 +2162,9 @@ def make_sales_invoice_for_ewaybill():
if not gst_account:
gst_settings.append("gst_accounts", {
"company": "_Test Company",
"cgst_account": "CGST - _TC",
"sgst_account": "SGST - _TC",
"igst_account": "IGST - _TC",
"cgst_account": "Output Tax CGST - _TC",
"sgst_account": "Output Tax SGST - _TC",
"igst_account": "Output Tax IGST - _TC",
})
gst_settings.save()
@@ -2115,6 +2174,7 @@ def make_sales_invoice_for_ewaybill():
si.distance = 2000
si.company_address = "_Test Address for Eway bill-Billing"
si.customer_address = "_Test Customer-Address for Eway bill-Shipping"
si.dispatch_address_name = "_Test Dispatch-Address for Eway bill-Shipping"
si.vehicle_no = "KA12KA1234"
si.gst_category = "Registered Regular"
si.mode_of_transport = 'Road'
@@ -2122,7 +2182,7 @@ def make_sales_invoice_for_ewaybill():
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "CGST - _TC",
"account_head": "Output Tax CGST - _TC",
"cost_center": "Main - _TC",
"description": "CGST @ 9.0",
"rate": 9
@@ -2130,7 +2190,7 @@ def make_sales_invoice_for_ewaybill():
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "SGST - _TC",
"account_head": "Output Tax SGST - _TC",
"cost_center": "Main - _TC",
"description": "SGST @ 9.0",
"rate": 9
@@ -2167,6 +2227,7 @@ def create_sales_invoice(**args):
si.currency=args.currency or "INR"
si.conversion_rate = args.conversion_rate or 1
si.naming_series = args.naming_series or "T-SINV-"
si.cost_center = args.parent_cost_center
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
@@ -2178,8 +2239,11 @@ def create_sales_invoice(**args):
"uom": args.uom or "Nos",
"stock_uom": args.uom or "Nos",
"rate": args.rate if args.get("rate") is not None else 100,
"price_list_rate": args.price_list_rate if args.get("price_list_rate") is not None else 100,
"income_account": args.income_account or "Sales - _TC",
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"discount_account": args.discount_account or None,
"discount_amount": args.discount_amount or 0,
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
"conversion_factor": 1

View File

@@ -1,235 +1,128 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-02-22 01:27:41",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"actions": [],
"creation": "2013-02-22 01:27:41",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"reference_type",
"reference_name",
"remarks",
"reference_row",
"col_break1",
"advance_amount",
"allocated_amount",
"exchange_gain_loss",
"ref_exchange_rate"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Type",
"length": 0,
"no_copy": 1,
"oldfieldname": "journal_voucher",
"oldfieldtype": "Link",
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "250px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "reference_type",
"fieldtype": "Link",
"label": "Reference Type",
"no_copy": 1,
"oldfieldname": "journal_voucher",
"oldfieldtype": "Link",
"options": "DocType",
"print_width": "250px",
"read_only": 1,
"width": "250px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Reference Name",
"length": 0,
"no_copy": 1,
"options": "reference_type",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"columns": 3,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"in_list_view": 1,
"label": "Reference Name",
"no_copy": 1,
"options": "reference_type",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 3,
"fieldname": "remarks",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Remarks",
"length": 0,
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 3,
"fieldname": "remarks",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Remarks",
"no_copy": 1,
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"print_width": "150px",
"read_only": 1,
"width": "150px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Row",
"length": 0,
"no_copy": 1,
"oldfieldname": "jv_detail_no",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "reference_row",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Row",
"no_copy": 1,
"oldfieldname": "jv_detail_no",
"oldfieldtype": "Data",
"print_hide": 1,
"print_width": "120px",
"read_only": 1,
"width": "120px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
"fieldname": "col_break1",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "advance_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Advance amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 2,
"fieldname": "advance_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Advance amount",
"no_copy": 1,
"oldfieldname": "advance_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_width": "120px",
"read_only": 1,
"width": "120px"
},
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Allocated amount",
"length": 0,
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "120px",
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"columns": 2,
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Allocated amount",
"no_copy": 1,
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
"options": "party_account_currency",
"print_width": "120px",
"width": "120px"
},
{
"fieldname": "exchange_gain_loss",
"fieldtype": "Currency",
"label": "Exchange Gain/Loss",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "ref_exchange_rate",
"fieldtype": "Float",
"label": "Reference Exchange Rate",
"non_negative": 1,
"read_only": 1
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
"modified": "2016-08-26 02:36:10.718057",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Advance",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"sort_order": "DESC",
"track_seen": 0
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-06-04 20:25:49.832052",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Advance",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -63,6 +63,7 @@
"finance_book",
"col_break4",
"expense_account",
"discount_account",
"deferred_revenue",
"deferred_revenue_account",
"service_stop_date",
@@ -821,12 +822,18 @@
"no_copy": 1,
"options": "currency",
"read_only": 1
},
{
"fieldname": "discount_account",
"fieldtype": "Link",
"label": "Discount Account",
"options": "Account"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-02-23 01:05:22.123527",
"modified": "2021-07-05 15:07:22.857128",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -9,7 +9,9 @@
"description",
"billing_hours",
"billing_amount",
"column_break_5",
"time_sheet",
"project_name",
"timesheet_detail"
],
"fields": [
@@ -61,11 +63,21 @@
"in_list_view": 1,
"label": "Description",
"read_only": 1
},
{
"fieldname": "column_break_5",
"fieldtype": "Column Break"
},
{
"fieldname": "project_name",
"fieldtype": "Data",
"label": "Project Name",
"read_only": 1
}
],
"istable": 1,
"links": [],
"modified": "2021-05-20 22:33:57.234846",
"modified": "2021-06-08 14:43:02.748981",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Timesheet",

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:17:44.329943",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"sales_partner"
],
"fields": [
{
"fieldname": "sales_partner",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Sales Partner ",
"options": "Sales Partner"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:43:37.532095",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Partner Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 SalesPartnerItem(Document):
pass

View File

@@ -27,7 +27,8 @@
"base_tax_amount",
"base_total",
"base_tax_amount_after_discount_amount",
"item_wise_tax_detail"
"item_wise_tax_detail",
"dont_recompute_tax"
],
"fields": [
{
@@ -195,17 +196,27 @@
},
{
"default": "0",
"depends_on": "eval:['Sales Taxes and Charges Template', 'Payment Entry'].includes(parent.doctype)",
"description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry",
"fieldname": "included_in_paid_amount",
"fieldtype": "Check",
"label": "Considered In Paid Amount"
},
{
"default": "0",
"fieldname": "dont_recompute_tax",
"fieldtype": "Check",
"hidden": 1,
"label": "Dont Recompute tax",
"print_hide": 1,
"read_only": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-06-09 11:48:04.691596",
"modified": "2021-07-27 12:40:59.051803",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",

View File

@@ -6,7 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax, validate_cost_center, validate_account_head
class SalesTaxesandChargesTemplate(Document):
def validate(self):
@@ -39,6 +39,8 @@ def valdiate_taxes_and_charges_template(doc):
for tax in doc.get("taxes"):
validate_taxes_and_charges(tax)
validate_account_head(tax, doc)
validate_cost_center(tax, doc)
validate_inclusive_tax(tax, doc)
def validate_disabled(doc):

View File

@@ -8,6 +8,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 6
},
@@ -16,6 +17,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 6.36
}
@@ -114,6 +116,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -122,6 +125,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}
@@ -137,6 +141,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -145,6 +150,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}
@@ -160,6 +166,7 @@
"charge_type": "On Net Total",
"description": "VAT",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 12
},
@@ -168,6 +175,7 @@
"charge_type": "On Net Total",
"description": "Service Tax",
"doctype": "Sales Taxes and Charges",
"cost_center": "Main - _TC",
"parentfield": "taxes",
"rate": 4
}

View File

@@ -78,7 +78,7 @@
"label": "Cost"
},
{
"depends_on": "eval:doc.price_determination==\"Based on price list\"",
"depends_on": "eval:doc.price_determination==\"Based On Price List\"",
"fieldname": "price_list",
"fieldtype": "Link",
"label": "Price List",
@@ -147,7 +147,7 @@
}
],
"links": [],
"modified": "2020-06-25 10:53:44.205774",
"modified": "2021-08-09 10:53:44.205774",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription Plan",

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:19:22.040795",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"supplier_group"
],
"fields": [
{
"fieldname": "supplier_group",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Supplier Group",
"options": "Supplier Group"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:43:59.877938",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Supplier Group Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 SupplierGroupItem(Document):
pass

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:18:54.758468",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"supplier"
],
"fields": [
{
"fieldname": "supplier",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Supplier",
"options": "Supplier"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:44:09.707778",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Supplier Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 SupplierItem(Document):
pass

View File

@@ -1,24 +1,6 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("customer", "customer_group", "customer_group" );
cur_frm.add_fetch("supplier", "supplier_group_name", "supplier_group" );
frappe.ui.form.on("Tax Rule", "tax_type", function(frm) {
frm.toggle_reqd("sales_tax_template", frm.doc.tax_type=="Sales");
frm.toggle_reqd("purchase_tax_template", frm.doc.tax_type=="Purchase");
})
frappe.ui.form.on("Tax Rule", "onload", function(frm) {
if(frm.doc.__islocal) {
frm.set_value("use_for_shopping_cart", 1);
}
})
frappe.ui.form.on("Tax Rule", "refresh", function(frm) {
frappe.ui.form.trigger("Tax Rule", "tax_type");
})
frappe.ui.form.on("Tax Rule", "customer", function(frm) {
if(frm.doc.customer) {
frappe.call({

File diff suppressed because it is too large Load Diff

View File

@@ -50,7 +50,7 @@ class TestTaxRule(unittest.TestCase):
tax_rule1 = make_tax_rule(customer_group= "All Customer Groups",
sales_tax_template = "_Test Sales Taxes and Charges Template - _TC", priority = 1, from_date = "2015-01-01")
tax_rule1.save()
self.assertEqual(get_tax_template("2015-01-01", {"customer_group" : "Commercial", "use_for_shopping_cart":0}),
self.assertEqual(get_tax_template("2015-01-01", {"customer_group" : "Commercial", "use_for_shopping_cart":1}),
"_Test Sales Taxes and Charges Template - _TC")
def test_conflict_with_overlapping_dates(self):

View File

@@ -1,263 +1,151 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "Prompt",
"beta": 0,
"creation": "2018-04-13 18:42:06.431683",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "Prompt",
"creation": "2018-04-13 18:42:06.431683",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"category_details_section",
"category_name",
"round_off_tax_amount",
"column_break_2",
"consider_party_ledger_amount",
"tax_on_excess_amount",
"section_break_8",
"rates",
"section_break_7",
"accounts"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "category_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Category Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"show_days": 1,
"show_seconds": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Tax Withholding Rates",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"show_days": 1,
"show_seconds": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rates",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Rates",
"length": 0,
"no_copy": 0,
"options": "Tax Withholding Rate",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"show_days": 1,
"show_seconds": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"label": "Account Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"show_days": 1,
"show_seconds": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Tax Withholding Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "accounts",
"fieldtype": "Table",
"label": "Accounts",
"options": "Tax Withholding Account",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "category_details_section",
"fieldtype": "Section Break",
"label": "Category Details",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"description": "Even invoices with apply tax withholding unchecked will be considered for checking cumulative threshold breach",
"fieldname": "consider_party_ledger_amount",
"fieldtype": "Check",
"label": "Consider Entire Party Ledger Amount",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"description": "Tax will be withheld only for amount exceeding the cumulative threshold",
"fieldname": "tax_on_excess_amount",
"fieldtype": "Check",
"label": "Only Deduct Tax On Excess Amount ",
"show_days": 1,
"show_seconds": 1
},
{
"description": "Checking this will round off the tax amount to the nearest integer",
"fieldname": "round_off_tax_amount",
"fieldtype": "Check",
"label": "Round Off Tax Amount",
"show_days": 1,
"show_seconds": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-07-17 22:53:26.193179",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
"name_case": "",
"owner": "Administrator",
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-07-27 21:47:34.396071",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Tax Withholding Category",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, getdate
from frappe.utils import flt, getdate, cint
from erpnext.accounts.utils import get_fiscal_year
class TaxWithholdingCategory(Document):
@@ -86,7 +86,10 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
"rate": tax_rate_detail.tax_withholding_rate,
"threshold": tax_rate_detail.single_threshold,
"cumulative_threshold": tax_rate_detail.cumulative_threshold,
"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category,
"consider_party_ledger_amount": tax_withholding.consider_party_ledger_amount,
"tax_on_excess_amount": tax_withholding.tax_on_excess_amount,
"round_off_tax_amount": tax_withholding.round_off_tax_amount
})
def get_tax_withholding_rates(tax_withholding, fiscal_year):
@@ -145,6 +148,7 @@ def get_lower_deduction_certificate(fiscal_year, pan_no):
def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None):
fiscal_year = fiscal_year_details[0]
vouchers = get_invoice_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
advance_vouchers = get_advance_vouchers(parties, fiscal_year, inv.company, party_type=party_type)
taxable_vouchers = vouchers + advance_vouchers
@@ -235,10 +239,18 @@ def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details):
def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers):
tds_amount = 0
invoice_filters = {
'name': ('in', vouchers),
'docstatus': 1
}
supp_credit_amt = frappe.db.get_value('Purchase Invoice', {
'name': ('in', vouchers), 'docstatus': 1, 'apply_tds': 1
}, 'sum(net_total)') or 0.0
field = 'sum(net_total)'
if not cint(tax_details.consider_party_ledger_amount):
invoice_filters.update({'apply_tds': 1})
field = 'sum(grand_total)'
supp_credit_amt = frappe.db.get_value('Purchase Invoice', invoice_filters, field) or 0.0
supp_jv_credit_amt = frappe.db.get_value('Journal Entry Account', {
'parent': ('in', vouchers), 'docstatus': 1,
@@ -255,6 +267,13 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
cumulative_threshold = tax_details.get('cumulative_threshold', 0)
if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)):
if (cumulative_threshold and supp_credit_amt >= cumulative_threshold) and cint(tax_details.tax_on_excess_amount):
# Get net total again as TDS is calculated on net total
# Grand is used to just check for threshold breach
net_total = frappe.db.get_value('Purchase Invoice', invoice_filters, 'sum(net_total)') or 0.0
net_total += inv.net_total
supp_credit_amt = net_total - cumulative_threshold
if ldc and is_valid_certificate(
ldc.valid_from, ldc.valid_upto,
inv.get('posting_date') or inv.get('transaction_date'), tax_deducted,
@@ -263,6 +282,9 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
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

View File

@@ -87,6 +87,31 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in invoices:
d.cancel()
def test_tax_withholding_category_checks(self):
invoices = []
frappe.db.set_value("Supplier", "Test TDS Supplier3", "tax_withholding_category", "New TDS Category")
# First Invoice with no tds check
pi = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000, do_not_save=True)
pi.apply_tds = 0
pi.save()
pi.submit()
invoices.append(pi)
# Second Invoice will apply TDS checked
pi1 = create_purchase_invoice(supplier = "Test TDS Supplier3", rate = 20000)
pi1.submit()
invoices.append(pi1)
# Cumulative threshold is 30000
# Threshold calculation should be on both the invoices
# TDS should be applied only on 1000
self.assertEqual(pi1.taxes[0].tax_amount, 1000)
for d in invoices:
d.cancel()
def test_cumulative_threshold_tcs(self):
frappe.db.set_value("Customer", "Test TCS Customer", "tax_withholding_category", "Cumulative Threshold TCS")
invoices = []
@@ -112,7 +137,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
si = create_sales_invoice(customer = "Test TCS Customer", rate=5000)
si.submit()
tcs_charged = sum([d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC'])
tcs_charged = sum(d.base_tax_amount for d in si.taxes if d.account_head == 'TCS - _TC')
self.assertEqual(tcs_charged, 500)
invoices.append(si)
@@ -195,7 +220,7 @@ def create_sales_invoice(**args):
def create_records():
# create a new suppliers
for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2', 'Test TDS Supplier3']:
if frappe.db.exists('Supplier', name):
continue
@@ -311,3 +336,23 @@ def create_tax_with_holding_category():
'account': 'TDS - _TC'
}]
}).insert()
if not frappe.db.exists("Tax Withholding Category", "New TDS Category"):
frappe.get_doc({
"doctype": "Tax Withholding Category",
"name": "New TDS Category",
"category_name": "New TDS Category",
"round_off_tax_amount": 1,
"consider_party_ledger_amount": 1,
"tax_on_excess_amount": 1,
"rates": [{
'fiscal_year': fiscal_year,
'tax_withholding_rate': 10,
'single_threshold': 0,
'cumulative_threshold': 30000
}],
"accounts": [{
'company': '_Test Company',
'account': 'TDS - _TC'
}]
}).insert()

View File

@@ -0,0 +1,31 @@
{
"actions": [],
"creation": "2021-05-06 16:16:51.885441",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"territory"
],
"fields": [
{
"fieldname": "territory",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Territory",
"options": "Territory"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-05-07 10:43:26.641030",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Territory Item",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -0,0 +1,8 @@
# 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 TerritoryItem(Document):
pass

View File

@@ -100,8 +100,8 @@ def merge_similar_entries(gl_map, precision=None):
return merged_gl_map
def check_if_in_list(gle, gl_map, dimensions=None):
account_head_fieldnames = ['party_type', 'party', 'against_voucher', 'against_voucher_type',
'cost_center', 'project']
account_head_fieldnames = ['voucher_detail_no', 'party', 'against_voucher',
'cost_center', 'against_voucher_type', 'party_type', 'project']
if dimensions:
account_head_fieldnames = account_head_fieldnames + dimensions
@@ -110,10 +110,12 @@ def check_if_in_list(gle, gl_map, dimensions=None):
same_head = True
if e.account != gle.account:
same_head = False
continue
for fieldname in account_head_fieldnames:
if cstr(e.get(fieldname)) != cstr(gle.get(fieldname)):
same_head = False
break
if same_head:
return e
@@ -143,16 +145,19 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
validate_expense_against_budget(args)
def validate_cwip_accounts(gl_map):
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
"""Validate that CWIP account are not used in Journal Entry"""
if gl_map and gl_map[0].voucher_type != "Journal Entry":
return
if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Capital Work in Progress' and is_group=0""")]
cwip_enabled = any(cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category", "enable_cwip_accounting"))
if cwip_enabled:
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Capital Work in Progress' and is_group=0""")]
for entry in gl_map:
if entry.account in cwip_accounts:
frappe.throw(
_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
for entry in gl_map:
if entry.account in cwip_accounts:
frappe.throw(
_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
def round_off_debit_credit(gl_map):
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),

View File

@@ -8,7 +8,7 @@ from frappe import _, msgprint, scrub
from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
from frappe.model.utils import get_fetch_values
from frappe.utils import (add_days, getdate, formatdate, date_diff,
add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day)
add_years, get_timestamp, nowdate, flt, cstr, add_months, get_last_day, cint)
from frappe.contacts.doctype.address.address import (get_address_display,
get_default_address, get_company_address)
from frappe.contacts.doctype.contact.contact import get_contact_details
@@ -58,7 +58,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
billing_address=party_address, shipping_address=shipping_address)
if fetch_payment_terms_template:
if cint(fetch_payment_terms_template):
party_details["payment_terms_template"] = get_payment_terms_template(party.name, party_type, company)
if not party_details.get("currency"):
@@ -457,7 +457,7 @@ def validate_party_frozen_disabled(party_type, party_name):
frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen)
elif party_type == "Employee":
if frappe.db.get_value("Employee", party_name, "status") == "Left":
if frappe.db.get_value("Employee", party_name, "status") != "Active":
frappe.msgprint(_("{0} {1} is not active").format(party_type, party_name), alert=True)
def get_timeline_data(doctype, name):
@@ -542,6 +542,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
select company, sum(debit_in_account_currency) - sum(credit_in_account_currency)
from `tabGL Entry`
where party_type = %s and party=%s
and is_cancelled = 0
group by company""", (party_type, party)))
for d in companies:

View File

@@ -99,7 +99,6 @@ class ReceivablePayableReport(object):
voucher_no = gle.voucher_no,
party = gle.party,
posting_date = gle.posting_date,
remarks = gle.remarks,
account_currency = gle.account_currency,
invoiced = 0.0,
paid = 0.0,
@@ -579,7 +578,7 @@ class ReceivablePayableReport(object):
self.gl_entries = frappe.db.sql("""
select
name, posting_date, account, party_type, party, voucher_type, voucher_no, cost_center,
against_voucher_type, against_voucher, account_currency, remarks, {0}
against_voucher_type, against_voucher, account_currency, {0}
from
`tabGL Entry`
where
@@ -792,8 +791,6 @@ class ReceivablePayableReport(object):
self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
options='Supplier Group')
self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200)
def add_column(self, label, fieldname=None, fieldtype='Currency', options=None, width=120):
if not fieldname: fieldname = scrub(label)
if fieldtype=='Currency': options='currency'

View File

@@ -397,6 +397,7 @@ def get_chart_data(filters, columns, data):
{'name': 'Budget', 'chartType': 'bar', 'values': budget_values},
{'name': 'Actual Expense', 'chartType': 'bar', 'values': actual_values}
]
}
},
'type' : 'bar'
}

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