Compare commits

...

948 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
Nabin Hait
d17217c4e2 Merge pull request #25831 from deepeshgarg007/tds_advance_payment_v13
feat: Tax deduction against advance payments
2021-06-10 20:25:30 +05:30
Nabin Hait
002ec69b2f Merge pull request #25961 from deepeshgarg007/dynamic_gst_rates
feat: Item Taxes based on net rate
2021-06-10 19:39:48 +05:30
Deepesh Garg
3b34fc4cce Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into tds_advance_payment_v13 2021-06-10 18:57:31 +05:30
Deepesh Garg
5434dd048b Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into dynamic_gst_rates 2021-06-10 18:56:39 +05:30
Deepesh Garg
0d49b6c211 Merge pull request #26004 from gavindsouza/patch-tests-v13
ci: Update Patch tests (backport)
2021-06-10 18:52:27 +05:30
Saqib
9a67141bfb fix(einvoicing): service item check (#26010) 2021-06-10 18:48:55 +05:30
Deepesh Garg
d52539798c Merge pull request #26009 from deepeshgarg007/account_balance_test
fix: Sort account balances by account name
2021-06-10 18:47:43 +05:30
Deepesh Garg
9a243ed469 fix: Sort account balances by account name 2021-06-10 18:16:46 +05:30
Deepesh Garg
a5c3427293 fix: Sort account balances by account name 2021-06-10 18:09:49 +05:30
Deepesh Garg
88176e65e4 fix: Check for gst_hsn_code 2021-06-10 17:31:28 +05:30
Gavin D'souza
137d08a9d7 fix: Manually link_fields from flags before rename_doc 2021-06-10 15:09:17 +05:30
Gavin D'souza
96f8ebc308 fix(patch): Handle NULL values from fieldtype change 2021-06-10 15:08:55 +05:30
Gavin D'souza
43a24f2aa8 ci: Update ERPNext backup patch test >= v10
* Generated v10 backup archive
    * used old v7 erpnext backup hosted via build.erpnext.com
    * upgraded to v10 frappe + erpnext
* Hosted backup on https://erpnext.com/files/v10-erpnext.sql.gz
2021-06-10 15:08:42 +05:30
Gavin D'souza
3dfbfe87e9 chore: Drop < v10 patches from list
v7 backup was restored and upgraded to latest v10.x.x branch. The patches run uptil the upgrade are removed in this change. This means only existing v10 sites are allowed direct upgrade to v13 and newer

There are older version patches still left since they're being used in later ERPNext versions too.
2021-06-10 15:07:56 +05:30
Gavin D'souza
aedf25ba46 chore: Drop old patches
v7 backup was restored and upgraded to latest v10.x.x branch. The
patches run uptil the upgrade are removed in this change. This means
only existing v10 sites are allowed direct upgrade to v13 and newer
2021-06-10 15:07:39 +05:30
rohitwaghchaure
8975c5241e Merge pull request #25988 from rohitwaghchaure/donot-copy-difference-account
fix: on click of duplicate button system has not copied the difference account
2021-06-10 14:39:56 +05:30
Deepesh Garg
882913ca4e Merge pull request #26000 from GangaManoj/gst-settings-card
fix: Only display GST card in Accounting Workspace if it's in India
2021-06-10 12:46:15 +05:30
Deepesh Garg
d063f9a5d1 fix: GL Entry ordering 2021-06-10 12:26:21 +05:30
GangaManoj
076bd5eaab fix: Only display GST card in Accounting Workspace if it's in India 2021-06-10 12:08:44 +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
Deepesh Garg
0b5fe1b5eb fix: Failing test case 2021-06-10 10:34:49 +05:30
Deepesh Garg
911818a9e2 fix: Add multiple fixes 2021-06-09 22:55:10 +05:30
Saqib
42557c4ad3 feat: cost-center wise period closing entry (#25766) 2021-06-09 19:48:31 +05:30
Saqib
26f0609390 feat: enable/disable gl entry posting for change given in pos (#25822) 2021-06-09 19:47:28 +05:30
Deepesh Garg
9e648183db fix: Test case 2021-06-09 18:26:16 +05:30
Deepesh Garg
7dabb6be30 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into tds_advance_payment_v13 2021-06-09 18:10:55 +05:30
Deepesh Garg
b57ebba3fd fix: Validate negative allocated amount in Payment Entry (#25799) 2021-06-09 17:56:41 +05:30
Deepesh Garg
4c1dad8207 fix: Debug tests 2021-06-09 14:18:23 +05:30
Deepesh Garg
8090965162 fix: Debug test 2021-06-09 13:45:42 +05:30
Deepesh Garg
758db793be Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into tds_advance_payment_v13 2021-06-09 13:39:07 +05:30
Deepesh Garg
bf5f87c2fe Merge pull request #25969 from deepeshgarg007/inernal_transfer_invoices_ignore
fix: Ignore internal transfer invoices from GST Reports
2021-06-09 13:32:52 +05:30
Deepesh Garg
be631d1caf Merge pull request #25986 from nextchamp-saqib/einvoicing-service-item-check
fix(e-invoicing): service item check
2021-06-09 13:00:43 +05:30
Anupam Kumar
21b8e2f0d8 fix: hiding Rounding Adjustment field (#25380)
* fix: hiding Rounding Adjustment field

* fix: updating purchase_invoice.json
2021-06-09 12:57:21 +05:30
Deepesh Garg
9a282aa593 Merge pull request #25858 from alyf-de/item-tax-templates
feat: Item Tax Templates for Germany
2021-06-09 12:50:27 +05:30
Rohit Waghchaure
99b583f688 fix: on click of duplicate button system copy the difference account from first row 2021-06-09 00:06:35 +05:30
Saqib Ansari
18eed58fc5 fix(e-invoicing): service item check 2021-06-08 20:52:14 +05:30
Rucha Mahabal
5ed2ef493a Merge pull request #25984 from pateljannat/quiz-fixes-v13
fix: Quiz fixes v13
2021-06-08 18:57:24 +05:30
pateljannat
7ace06ac21 fix: sider 2021-06-08 18:26:23 +05:30
Ganga Manoj
0ea4d850e1 fix: Allow all System Managers to delete company transactions (#25834) 2021-06-08 17:23:44 +05:30
pateljannat
bbf07d9214 fix: quiz timer issues 2021-06-08 17:05:44 +05:30
Deepesh Garg
e4fcc5562f refactor: Advance taxes and charges calculation 2021-06-08 16:35:47 +05:30
Sagar Vora
3f1231b77c Merge pull request #25981 from resilient-tech/ssa-selection-v13
fix: choose correct Salary Structure Assignment when getting data for formula eval
2021-06-08 15:21:10 +05:30
Sagar Vora
062e247353 test: remove unused imports 2021-06-08 14:43:28 +05:30
Sagar Vora
ca205be5ac fix: tests 2021-06-08 14:43:28 +05:30
Sagar Vora
0e5e1350b2 perf: use frappe.get_value with wildcard instead of another frappe.get_doc call 2021-06-08 14:43:28 +05:30
Sagar Vora
74818c7b62 fix: improve filter for from_date; validation for joining and relieving date 2021-06-08 14:43:28 +05:30
Sagar Vora
447c978757 fix: choose correct Salary Structure Assignment when getting data for formula eval 2021-06-08 14:43:28 +05:30
Anuja Pawar
d4398fd84a fix: update cost center from pos (#25971) 2021-06-07 16:20:21 +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
rohitwaghchaure
cf7baeab16 Merge pull request #25956 from rohitwaghchaure/fixed-conversion-factor-issue
fix: custom conversion factor field not mapped from job card to stock entry
2021-06-07 11:45:44 +05:30
Deepesh Garg
6f2dacc60c Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into tds_advance_payment_v13 2021-06-06 19:31:50 +05:30
Deepesh Garg
7a20c3b92a fix: Ignore internal transfer inoices from GST Reports 2021-06-06 19:23:21 +05:30
Deepesh Garg
18be767f75 fix: Remove invalid test 2021-06-06 13:25:34 +05:30
Saqib
d689068d82 Merge pull request #25928 from nextchamp-saqib/pos-fixes-8
fix(pos): multiple pos issues
2021-06-06 11:25:29 +05:30
Saqib Ansari
3f32969bee fix(pos): broken image in item details section 2021-06-06 11:18:20 +05:30
Saqib Ansari
bc46a9772d fix(pos): cash shortcuts not working 2021-06-06 11:11:07 +05:30
Saqib Ansari
a85c2c16b4 fix(pos): item rate precision in item selector 2021-06-06 11:07:20 +05:30
Deepesh Garg
3646c301ed fix: Linting issues 2021-06-05 13:21:03 +05:30
Deepesh Garg
e8a78bd43d fix: Add test cases 2021-06-05 13:16:39 +05:30
Deepesh Garg
8a7e283926 feat: Item Taxes based on net rate 2021-06-04 22:53:26 +05:30
barredterra
572b6df0f2 Merge branch 'version-13-hotfix' into item-tax-templates 2021-06-04 16:55:11 +02:00
18alantom
672c8bb112 feature: report for cost of goods sold by item group 2021-06-04 16:44:30 +05:30
Ankush Menat
215516f819 fix: AttributeError: 'PurchaseReceiptItem' object has no attribute 'purchase_invoice' (#25902) (#25957)
* fix: AttributeError: 'PurchaseReceiptItem' object has no attribute 'purchase_invoice'

This error occurs when upgrading from erpnext 13.0.1 to 13.4.0 after typing
bench update --patch --reset

* fix(minor): use .get instead of getattr

Co-authored-by: D Tim Cummings <tim@triptera.com.au>
2021-06-04 13:09:14 +05:30
Rucha Mahabal
3f45901f25 fix: invalid 'depends_on' expression in opportunity (#25955) 2021-06-04 11:16:38 +05:30
Rohit Waghchaure
af4794b2d1 fix: custom conversion factor field not mapped from job card to stock entry 2021-06-04 10:53:44 +05:30
Saqib
c6e016e545 fix: wrong round off gl entry posted in case of purchase invoice (#25775) 2021-06-04 10:08:22 +05:30
Saqib Ansari
4a1e270072 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into pos-fixes-8 2021-06-04 10:04:09 +05:30
Saqib Ansari
48036b4bab fix: invoices can alter profit and loss of a closed year 2021-06-04 09:54:34 +05:30
rohitwaghchaure
25b953ad16 Merge pull request #25854 from rohitwaghchaure/fixed-timeout-error-in-repost-item-valuation
fix: timeout error in the repost item valuation
2021-06-03 22:14:22 +05:30
rohitwaghchaure
c59371ab0c fix: filter type for item query (#25942) 2021-06-03 20:02:58 +05:30
barredterra
c99eaf106e Merge branch 'version-13-hotfix' into item-tax-templates 2021-06-03 14:17:43 +02:00
Rohit Waghchaure
10558344b0 fix: timeout error in the repost item valuation 2021-06-03 16:34:31 +05:30
Marica
7437748a1d Merge pull request #25805 from ankush/refactor_item
refactor: item doctype
2021-06-03 14:23:18 +05:30
Saqib Ansari
81b9a5ee47 fix(pos): cannot cancel consolidated sales invoice 2021-06-03 12:59:09 +05:30
Saqib Ansari
311b378328 fix(pos): searching items with barcode or serial no 2021-06-03 12:58:53 +05:30
rohitwaghchaure
40b90e5b6e Merge pull request #25478 from noahjacob/prod_plan_feat
feat: Added check box to combine items with same BOM
2021-06-03 12:37:02 +05:30
Marica
e7d9200e0f Merge pull request #25221 from Alchez/dev-quality-inspection-accounts
feat: create Quality Inspections from account and stock documents
2021-06-03 01:39:05 +05:30
barredterra
9affcd8f54 Merge branch 'version-13-hotfix' into item-tax-templates 2021-06-02 17:54:02 +02:00
Nabin Hait
88d94dbf0a Merge pull request #25915 from rohitwaghchaure/fixed-work-order-no-able-to-select-item
fix: not able to select the item code in work order
2021-06-02 19:00:34 +05:30
Raffael Meyer
f6627550d1 fix: remove wrong tax_category 2021-06-02 15:17:00 +02:00
barredterra
3c748efae3 feat: add Item Tax Templates for german COAs "SKR03" and "SKR04" 2021-06-02 13:27:15 +02:00
barredterra
b6f27a4cae feat: set is_default for german tax templates 2021-06-02 13:20:33 +02:00
barredterra
f259bf48aa refactor: make tax category 2021-06-02 13:20:03 +02:00
barredterra
e3557ff131 Merge branch 'version-13-hotfix' into item-tax-templates 2021-06-02 12:17:27 +02:00
Rohan Bansal
a06ec03efc test: add test for new QI function 2021-06-02 14:55:31 +05:30
Rohan Bansal
11aff80dea Merge remote-tracking branch 'upstream/version-13-hotfix' into dev-quality-inspection-accounts 2021-06-02 14:22:32 +05:30
Rohit Waghchaure
721b4130db fix: not able to select the item code in work order 2021-06-02 14:13:09 +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
Fisher Yu
865663857c fix: chart of accounts importer always error (#25882)
* fix: chart of accounts importer always error 

chart of accounts importer always error Parent Account Missing

* Update chart_of_accounts_importer.py
2021-06-01 12:15:58 +05:30
Ankush Menat
2c7fac0e76 fix: reload doc for possible future schema changes (#25904) 2021-06-01 11:56:00 +05:30
Deepesh Garg
2f5885627d fix: Labeling and other fixes 2021-06-01 11:07:18 +05:30
Jannat Patel
1175e0686b refactor: leave balance report (#25771)
* refactor: leave balance report

* refactor: sql to orm
2021-06-01 10:53:00 +05:30
Ganga Manoj
c8b34798fe fix(Delivery Note): Assign Product Bundle's conversion_factor to Packed Items (#25840) 2021-06-01 10:44:26 +05:30
rohitwaghchaure
970f00922d Merge pull request #25898 from anupamvs/stock-reconciliation
fix: featching serialized items
2021-05-31 20:00:35 +05:30
Jannat Patel
022b5c973a fix: wrap dates in getdate for leave application (#25899)
* fix: wrap dates in getdate for leave application

* fix: translation issue

* fix: replaced today with getdate
2021-05-31 19:49:53 +05:30
Ganga Manoj
908b0090e9 fix: Create POS Invoice for Product Bundles (#25847)
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-05-31 19:49:03 +05:30
Deepesh Garg
0ea6725baa fix: Rename Loan Management workspace to Loans (#25856) 2021-05-31 19:48:31 +05:30
Anupam
0358b64743 fix: featching serialized items 2021-05-31 15:59:32 +05:30
Raffael Meyer
80540d38ba fix: add_deduct_tax in Purchase Taxes setup (#25871) 2021-05-31 15:36:20 +05:30
Saqib
89f621baa4 fix(pos): closing entry shows incorrect expected amount (#25868) 2021-05-31 09:56:49 +05:30
Rucha Mahabal
3be28054de refactor: Vehicle Expenses Report (#25727)
* refactor: Vehicle Expense Report

* test: Vehicle Expenses Report

* feat: Added Employee filter to report

- fix Vehicle Log form view

* fix: set currency fieldtype for chart data

- added filters for employee and vehicle

* fix: service expenses not getting set
2021-05-31 09:11:42 +05:30
Marica
42b2ea556f Merge pull request #25358 from noahjacob/maintenance_feat
refactor: maintenance schedule and visit enhancements.
2021-05-30 01:20:30 +05:30
Deepesh Garg
48b1a82fa1 fix: Add accounts and templates for reverse charge 2021-05-29 23:54:51 +05:30
Deepesh Garg
ea4f8102e8 Merge pull request #25869 from nextchamp-saqib/plaid-link-reset
fix(plaid): cannot reset plaid link for a bank account
2021-05-29 20:05:25 +05:30
Deepesh Garg
d067e25dad Merge pull request #25828 from Anuja-pawar/issue-summary-report-fix
fix: Add Hold status column in the Issue Summary Report
2021-05-29 19:24:15 +05:30
Deepesh Garg
c3d8115ca1 Merge pull request #25849 from nextchamp-saqib/pos-rate-as-identifier
fix(pos): cannot add same item with different rates
2021-05-29 17:33:11 +05:30
Deepesh Garg
5483f21fe7 Merge pull request #25872 from nextchamp-saqib/fix-pos-broken-img
fix(pos): rendering of broken image on pos
2021-05-29 17:28:03 +05:30
Ankush Menat
431d3295b4 fix: use dictionary filter instead of list (#25874)
Item query doesn't support list filter anymore.
2021-05-28 21:12:25 +05:30
Deepesh Garg
fb9cb0fd23 Merge pull request #25866 from deepeshgarg007/itc_reversa_address
fix(India): Show only company addresses for ITC reversal entry
2021-05-28 18:46:09 +05:30
Saqib Ansari
b72b4c0bf9 fix(pos): rendering of broken image on pos 2021-05-28 17:38:01 +05:30
Noah Jacob
6fb218e033 refactor: suggested changes 2021-05-28 16:15:50 +05:30
Saqib Ansari
05386ff12f chore: remove unwanted method 2021-05-28 12:58:18 +05:30
Deepesh Garg
20be7fb93d fix(India): Show only company addresses for ITC reversal entry 2021-05-28 11:57:38 +05:30
Saqib Ansari
bbce2e91a3 fix: reset plaid link button 2021-05-28 11:56:47 +05:30
Saqib Ansari
d24eccd623 fix(plaid): cannot reset plaid link for a bank account 2021-05-28 11:36:24 +05:30
Suraj Shetty
faa25166a9 revert: "ci: Do not generate coverage report for hotfix branch"
Reverts: bcf116422a
2021-05-28 11:23:18 +05:30
noahjacob
0b02f1335f refactor: removed redundant links in test case 2021-05-28 11:04:34 +05:30
noahjacob
d071586589 refactor: removed maintenance schedule detail link 2021-05-28 10:54:35 +05:30
noahjacob
7fa045c1c9 refactor: using parent form links of maintenance schedule 2021-05-28 10:54:35 +05:30
noahjacob
3bca90dbe6 refactor: updated mapping for maintenance schedule links in maintenance visit 2021-05-28 10:54:22 +05:30
Suraj Shetty
68b050de97 Merge pull request #25863 from surajshetty3416/website-theme-fixes-version-13-hotfix 2021-05-28 10:48:23 +05:30
Ganga Manoj
17736afab5 fix(POS): Fix stock availability calculation if negative_stock_allowed is checked (#25859) 2021-05-28 10:03:41 +05:30
Ganga Manoj
8a776a63cd fix(POS): Add Product Bundles to POS item search (#25860) 2021-05-28 09:56:30 +05:30
Suraj Shetty
24f2d58f53 Merge pull request #25862 from surajshetty3416/parallel-distributed-testing-version-13-hotfix 2021-05-28 09:40:58 +05:30
Suraj Shetty
f4db3139b7 refactor: Use css variables for breakpoint value 2021-05-28 09:22:46 +05:30
prssanna
c4d4be3265 fix: ensure website theme is applied correctly 2021-05-28 09:22:45 +05:30
Suraj Shetty
bcf116422a ci: Do not generate coverage report for hotfix branch 2021-05-28 09:12:24 +05:30
Suraj Shetty
85aeca1443 ci: Update Python version to 3.7 2021-05-28 09:10:34 +05:30
Suraj Shetty
6da2212e2d ci: Update frappe branch 2021-05-28 09:10:34 +05:30
Suraj Shetty
113a6f3d80 fix: Use frappe.safe_eval instead of eval 2021-05-28 09:10:34 +05:30
Suraj Shetty
77f2686142 ci: Use only 3 containers for now 2021-05-28 09:10:34 +05:30
Suraj Shetty
b9a8afc234 ci: Add test orchestrator URL 2021-05-28 09:10:34 +05:30
Suraj Shetty
96542c3d04 style: Fix sider issues 2021-05-28 09:10:34 +05:30
Suraj Shetty
273589e835 test: Fix a case where test used to fail due to holiday list
- fixes: "Please set a default Holiday List for Employee EMP-00009 or Company Wind Power LLC" error
2021-05-28 09:10:33 +05:30
Suraj Shetty
54354a84e1 test: Fix permission error 2021-05-28 09:10:33 +05:30
Suraj Shetty
d48ea663d9 test: Fix test name
- Rename TestSubcontractedItemToBeReceived > TestSubcontractedItemToBeTransferred
2021-05-28 09:10:33 +05:30
Suraj Shetty
d1a13ec050 test: Fix valuation rate for raw materials 2021-05-28 09:10:33 +05:30
Suraj Shetty
a891d6eed2 fix: allow_zero_valuation_rate for rejected qty 2021-05-28 09:10:33 +05:30
Suraj Shetty
b3e647feca fix: Pass ORCHESTRATOR_URL via secrets 2021-05-28 09:10:33 +05:30
Suraj Shetty
19c5fd72d6 refactor: Rename assertEquals to assertEqual to avoid deprecation warnings 2021-05-28 09:10:33 +05:30
Suraj Shetty
a70e11450e ci: Check limits 2021-05-28 09:09:36 +05:30
Suraj Shetty
ab8816e11d test: Fix test dependency 2021-05-28 09:09:36 +05:30
Suraj Shetty
c79f5d7514 ci: Try parallel testing with orchestrator 2021-05-28 09:09:36 +05:30
Suraj Shetty
175cb27bcb test: Pass ConflictingTaxRule during tax rule test 2021-05-28 09:09:36 +05:30
Suraj Shetty
8696580254 ci: Fix coveralls 2021-05-28 09:09:36 +05:30
Suraj Shetty
6ca8989013 ci: Disble failfast temporarily 2021-05-28 09:09:36 +05:30
Suraj Shetty
5e88b14a01 chore: Debug 2021-05-28 09:09:36 +05:30
Suraj Shetty
b4c958caf0 chore: Debug 2021-05-28 09:09:36 +05:30
Suraj Shetty
3b69aa80fc ci: Enable coveralls 2021-05-28 09:09:36 +05:30
Suraj Shetty
c26d41acf9 chore: Remove unnecessary print statements 2021-05-28 09:09:36 +05:30
Suraj Shetty
232cd28d67 test: Fix dependencies 2021-05-28 09:07:57 +05:30
Suraj Shetty
7b74985a54 test: Fix test_dependencies 2021-05-28 09:07:57 +05:30
Suraj Shetty
0f3d862ba9 chore: Debug 2021-05-28 09:07:57 +05:30
Suraj Shetty
85dd5d2252 chore: Debug 2021-05-28 09:07:57 +05:30
Suraj Shetty
34e620fb5b test: Fix dependency 2021-05-28 09:07:57 +05:30
Suraj Shetty
dd15304921 fix: Frappe branch 2021-05-28 09:07:57 +05:30
Suraj Shetty
591f3f0bb9 ci: Try Parallel tests 2021-05-28 09:07:57 +05:30
Deepesh Garg
a150645b57 fix: Remove GL Entry from print 2021-05-27 20:10:50 +05:30
Deepesh Garg
2e83cb77ca fix: Split GL Entry 2021-05-27 20:09:45 +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
barredterra
50794407b4 feat: Item Tax Templates for Germany 2021-05-27 14:17:53 +02:00
barredterra
86ee3ebb09 feat: create tax category during taxes setup 2021-05-27 14:16:26 +02:00
barredterra
46d39d27aa fix: validate company in taxes setup 2021-05-27 14:16:01 +02:00
anushka19
04dfaf3b2a fix: Broken help links fixed 2021-05-27 17:45:37 +05:30
Deepesh Garg
740c68d075 fix: Debug Test 2021-05-27 17:43:53 +05:30
noahjacob
fbc8694291 refactor: added maintenance schedule links to parent form 2021-05-27 17:37:57 +05:30
noahjacob
bd783e8072 refactor: renamed item_ref to item_reference 2021-05-27 17:34:16 +05:30
noahjacob
9e4c28852e refactor: added maintenance visit to maintenance schedule dashboard 2021-05-27 17:25:50 +05:30
Deepesh Garg
5dad72260f Merge pull request #25855 from Anuja-pawar/fix-ageing-report-psoa
fix: ageing error in PSOA
2021-05-27 17:24:04 +05:30
Anuja P
bb0a40b995 fix: ageing error in PSOA 2021-05-27 17:15:47 +05:30
Deepesh Garg
ea18230274 fix: Update GL Entry ordering 2021-05-27 16:40:37 +05:30
Saqib Ansari
3382655b5e fix: sider issues 2021-05-27 14:27:38 +05:30
Saqib Ansari
45a89a7c67 fix(pos): cannot add same item with different rates 2021-05-27 13:49:45 +05:30
Deepesh Garg
be3671fe7b fix: Create new supplier for test case 2021-05-27 13:27:17 +05:30
Anuja P
e2059fb9f6 fix: spaces to tabs 2021-05-26 20:07:53 +05:30
Anuja P
5e4128e70c fix: patch for existing issues 2021-05-26 20:03:14 +05:30
noahjacob
dc51388666 style: fixed indentations and formatting 2021-05-26 18:28:24 +05:30
Rohan Bansal
9857d63523 fix: add requested changes 2021-05-26 15:41:36 +05:30
Rohan Bansal
1e3a3b27c6 style: semgrep issues 2021-05-26 15:18:10 +05:30
Rohan Bansal
1cdf5a0dba fix: add requested changes 2021-05-26 14:42:15 +05:30
Rohan Bansal
c5b074269a Merge remote-tracking branch 'upstream/version-13-hotfix' into dev-quality-inspection-accounts 2021-05-26 14:32:14 +05:30
Marica
477a90e2ac Merge pull request #25833 from ankush/translation_fixes
fix(ux): fix unstranslated text in msgprint/throw
2021-05-26 14:12:36 +05:30
Marica
7342eb64e9 Merge pull request #25810 from marination/se-supplier-customer
chore: Cleanup Customer and Supplier Details section in Stock Entry
2021-05-26 14:10:41 +05:30
Anupam Kumar
349ef8274b fix: student invalid password reset link (#25826) 2021-05-26 12:14:02 +05:30
Deepesh Garg
36a11bf9ce Merge pull request #25841 from nextchamp-saqib/fix(gstr-1)--incorrect-gstin-fetched-incase-of-branch-company-address
fix(gstr-1): incorrect gstin fetched incase of branch company address
2021-05-26 11:20:30 +05:30
Marica
be157e7467 Merge branch 'version-13-hotfix' into se-supplier-customer 2021-05-26 11:19:50 +05:30
Anurag Mishra
2e0e4a7861 refactor: Additional Salary form clean up (#25785)
* feat: additional salary clean up

* fix: Label and description

* fix: labels

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-05-26 11:13:19 +05:30
Anuja P
db5217e48e fix: renaming hold to on hold 2021-05-26 11:09:48 +05:30
Saqib Ansari
0e804e292a fix(gstr-1): incorrect gstin fetched incase of branch company address 2021-05-26 10:54:16 +05:30
Anuja P
f3f87886a9 Merge branch 'version-13-hotfix' of https://github.com/frappe/erpnext into issue-summary-report-fix 2021-05-26 10:21:46 +05:30
Deepesh Garg
5e27c7dae2 fix: Add non group filter for account 2021-05-25 22:34:58 +05:30
Deepesh Garg
8fddd0f0c1 fix: Update TDS rate for test 2021-05-25 22:03:50 +05:30
Ankush Menat
ff96bdf0c1 fix(ux): fix unstranslated text in msgprint/throw 2021-05-25 20:59:20 +05:30
Deepesh Garg
84f270e732 fix: Remove unwanted commits 2021-05-25 18:03:42 +05:30
noahjacob
73e41c0bd6 refactor: suggested changes 2021-05-25 18:01:47 +05:30
Deepesh Garg
55a3fb57dd fix: Linting Issues 2021-05-25 17:40:06 +05:30
Deepesh Garg
36d47f97f4 fix: Linting issues 2021-05-25 17:40:04 +05:30
Deepesh Garg
6f84cee6fe fix: Uncommentt test 2021-05-25 17:39:06 +05:30
Deepesh Garg
b07f7d1b70 fix: Linting and other fixes 2021-05-25 17:39:04 +05:30
Deepesh Garg
c9da1fc568 chore: Test case for adance TDS allocation 2021-05-25 17:37:17 +05:30
Deepesh Garg
a23aaf43f4 fix: Allocate advance taxes only for payment entry 2021-05-25 17:36:06 +05:30
Deepesh Garg
e2f83ffaa4 fix: Linting fixes and other checks 2021-05-25 17:35:41 +05:30
Deepesh Garg
77dcee9d67 fix: Test Cases 2021-05-25 17:35:15 +05:30
Deepesh Garg
fd380d34f9 fix: Linting errors 2021-05-25 17:35:05 +05:30
Deepesh Garg
a87e3fcb7c fix: TDS report cleanup 2021-05-25 17:34:45 +05:30
Deepesh Garg
79b422c0a9 fix: Advance TDS in TDS payable monthly report 2021-05-25 17:33:59 +05:30
Deepesh Garg
d18dde7757 fix: Add tds in PO and code cleanup 2021-05-25 17:32:28 +05:30
Deepesh Garg
c26de28613 fix: TDS against Purhase Orders 2021-05-25 17:25:13 +05:30
Deepesh Garg
61c5e478af feat: Tax deduction against advance payments 2021-05-25 17:20:52 +05:30
Deepesh Garg
c9aa726818 feat: Tax deduction against advance payments 2021-05-25 17:17:40 +05:30
Anuja P
3efd411ddb fix: Hold status is added in the report 2021-05-25 16:24:01 +05:30
Ankush Menat
15f8a0fb22 test: fix flaky test 2021-05-24 17:55:39 +05:30
Ankush Menat
3aed662f46 chore: translation / semgrep / sider fixes 2021-05-24 17:55:39 +05:30
Ankush Menat
c15fef571f test: item naming series behaviour 2021-05-24 17:55:39 +05:30
Ankush Menat
76dd6e9046 test: contextmanager to change settings 2021-05-24 17:55:39 +05:30
Ankush Menat
42e057d079 test: add test for get_timeline_data in item 2021-05-24 17:55:38 +05:30
Ankush Menat
e971b4592e test: add test for is_stock_item 2021-05-24 17:55:38 +05:30
Ankush Menat
57266a7343 refactor: check_stock_uom_with_bin 2021-05-24 17:55:38 +05:30
Ankush Menat
fc54cf68ac test: add tests for checking stock_uom with bin 2021-05-24 17:55:38 +05:30
Ankush Menat
4e360f805f test: hoist defaults to function signature 2021-05-24 17:55:38 +05:30
Ankush Menat
a11a8e8ab2 chore: add blame ignore file 2021-05-24 17:55:38 +05:30
Ankush Menat
eb17732876 test: add test for item attribute completion 2021-05-24 17:55:37 +05:30
Ankush Menat
f5a937bc45 test: check index creation on item table 2021-05-24 17:55:37 +05:30
Ankush Menat
b9fa12d572 test: add tests for uom conversion function 2021-05-24 17:55:37 +05:30
Ankush Menat
019be66b7b fix: consider all UOMs for intermediate conversion
- Using `get_value` will restrict intermediate UOM to first UOM that is
  found.
- A self join is required to truly capture the required behaviour.
- Add explanation and examples.
2021-05-24 17:55:37 +05:30
Ankush Menat
0d7f54c6c2 refactor: simplify UOM conversion logic
- Remove unnecessary sql query
- Remove convoluted matching logic and be explcitiy while querying.
- better variable names for understanding matching cases
2021-05-24 17:55:37 +05:30
Ankush Menat
297dc5e345 perf: add basic optimisation for uom conversion 2021-05-24 17:55:37 +05:30
Ankush Menat
958d485ba4 refactor: msgprint(raise_exception)->frappe.throw 2021-05-24 17:55:36 +05:30
Ankush Menat
ccbde0efa0 refactor: use enumerate instead of trackign index
also removed dead code
2021-05-24 17:55:36 +05:30
Ankush Menat
44c489223b chore: remove py2 compat code 2021-05-24 17:55:18 +05:30
noahjacob
bf1b3b89d1 refactor: updated conditional visibility of check box 2021-05-24 17:03:15 +05:30
marination
c12264f6bc chore: Cleanup Customer and Supplier Details section in Stock Entry
- Changed depends on value to "Send to Subcontractor" for supplier fields
- Removed Customer fields as they are not relevant to any Stock Entry purpose
- Renamed section to "Supplier Details" visibe on subcontracting transfer
2021-05-24 13:20:22 +05:30
Ankush Menat
c229ac9322 refactor: add guard clause for readability
Both functions only execute based on a condition. In such cases
condition should immediately exit the function, this is called "guard
clause" and helps in readability (less indent, and easy to "exit" when
reading the code.
2021-05-23 16:31:29 +05:30
Ankush Menat
4b484d741d refactor: use is_new() instead of __islocal
Interface over implementation.
2021-05-23 16:31:29 +05:30
Ankush Menat
931c886f92 fix: not checking all fields
`break` will break out of the loop without checking remaining fields.
2021-05-23 16:31:29 +05:30
Ankush Menat
83e6e2e68a refactor: add guard clause for readability 2021-05-23 16:31:29 +05:30
Ankush Menat
0b4858d8e5 refactor: eliminate unnecessary loop, container casts 2021-05-23 16:31:29 +05:30
Ankush Menat
ad58a8164a refactor: code cleanup
minor fixes for improving code quality
2021-05-23 16:31:29 +05:30
Ankush Menat
4a2dbd4885 refactor: cleanup get_timeline_data, remove py2 2021-05-23 16:31:28 +05:30
Ankush Menat
330353a5ce refactor: use frappe.throw instread of recreating
_msgprint was basically duplicating behvaiour of frappe.throw
2021-05-23 16:31:16 +05:30
noahjacob
f0e6a16910 test: updated test for generated schedule dates 2021-05-20 19:29:12 +05:30
noahjacob
0169cd845a fix: sider 2021-05-20 15:40:07 +05:30
noahjacob
08598238d7 refactor: suggested changes 2021-05-20 13:23:10 +05:30
noahjacob
516c789127 refactor: variable names and suggested changes 2021-05-19 16:01:39 +05:30
noahjacob
50f52dfbcb refactor: variable names and refactored cancel function into submit function 2021-05-09 20:04:06 +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
noahjacob
c0352010d3 test: creating schedule and visit 2021-04-30 14:09:30 +05:30
noahjacob
7ad66caf7f refactor: migrated calculation and validation logic in js to py 2021-04-30 11:43:38 +05:30
noahjacob
90c667205a test: added on_cancel test 2021-04-29 13:06:04 +05:30
noahjacob
93c22ebbb9 refactor: created separate function to update work_order on cancel 2021-04-29 12:57:41 +05:30
noahjacob
56f697052c test: added test case for combining items 2021-04-28 20:12:33 +05:30
noahjacob
b7ca913904 fix: Added Item Reference field to link tables and update work_order_qty 2021-04-28 19:27:20 +05:30
noahjacob
82905166d9 fix: Fixed updating sales order work qty after cancelling work order 2021-04-28 10:14:36 +05:30
noahjacob
1e912db3bb feat: Added check box to combine items 2021-04-26 16:01:17 +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
noahjacob
fa9629c1e1 fix: Updated forms and fixed an error. 2021-04-21 11:29:40 +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
noahjacob
57f487a16b fix: Updated serial_no filters in maintenance visit. 2021-04-20 13:51:34 +05:30
noahjacob
5d7d338d2a feat: Schedule status is now updated on submitting a visit. 2021-04-19 18:39:34 +05:30
noahjacob
9a0a561ec6 feat: Created Dialog Box on trying to create a maintenance visit. 2021-04-19 16:42:50 +05:30
noahjacob
5ebc6abfad feat: Sales Person field is now editable after submitting. 2021-04-16 16:59:10 +05:30
noahjacob
e6fd3b86bd fix: fixed sider issues and translation syntax. 2021-04-16 15:48:36 +05:30
noahjacob
2c802720c3 feat: Automated setting end_date based on periodicity, no of visits and improved ux. 2021-04-15 20:31:18 +05:30
noahjacob
1ac471e04f feat: generate schedule is also triggered on save. 2021-04-15 16:48:01 +05:30
Marica
4e25aa77dd Merge branch 'develop' into dev-quality-inspection-accounts 2021-04-14 19:06:14 +05:30
Rohan Bansal
03f711e3a2 style: sider issues 2021-04-14 14:41:55 +05:30
Rohan Bansal
7f8b95efe8 fix: move QI logic to stock module 2021-04-14 14:15:45 +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
Rohan Bansal
a93b514b2f feat: create Quality Inspections from account and stock documents 2021-04-06 17:20:16 +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
1014 changed files with 25593 additions and 24143 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
}
}

12
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,12 @@
# Since version 2.23 (released in August 2019), git-blame has a feature
# to ignore or bypass certain commits.
#
# This file contains a list of commits that are not likely what you
# are looking for in a blame, such as mass reformatting or renaming.
# You can set this file as a default ignore file for blame by running
# the following command.
#
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
# This commit just changes spaces to tabs for indentation in some files
5f473611bd6ed57703716244a054d3fb5ba9cd23

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}}"

73
.github/workflows/patch.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Patch
on: [pull_request, workflow_dispatch]
jobs:
test:
runs-on: ubuntu-18.04
name: Patch Test
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.6
- 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: Install
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
- name: Run Patch Tests
run: |
cd ~/frappe-bench/
wget https://erpnext.com/files/v10-erpnext.sql.gz
bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz
bench --site test_site migrate

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

View File

@@ -1,6 +1,6 @@
name: CI
name: Server
on: [pull_request, workflow_dispatch, push]
on: [pull_request, workflow_dispatch]
jobs:
test:
@@ -10,15 +10,9 @@ jobs:
fail-fast: false
matrix:
include:
- TYPE: "server"
JOB_NAME: "Server"
RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --coverage
- TYPE: "patch"
JOB_NAME: "Patch"
RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz && bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
container: [1, 2, 3]
name: ${{ matrix.JOB_NAME }}
name: Python Unit Tests
services:
mysql:
@@ -36,7 +30,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.6
python-version: 3.7
- name: Add to Hosts
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
@@ -49,6 +43,7 @@ jobs:
restore-keys: |
${{ runner.os }}-pip-
${{ runner.os }}-
- name: Cache node modules
uses: actions/cache@v2
env:
@@ -60,6 +55,7 @@ jobs:
${{ 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)"
@@ -76,33 +72,39 @@ jobs:
run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
- name: Run Tests
run: ${{ matrix.RUN_COMMAND }}
run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage
env:
TYPE: ${{ matrix.TYPE }}
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
- name: Coverage - Pull Request
if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
- name: Upload Coverage Data
run: |
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
cd ${GITHUB_WORKSPACE}
pip install coveralls==2.2.0
pip install coverage==4.5.4
coveralls --service=github
pip3 install coverage==5.5
pip3 install coveralls==3.0.1
coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
COVERALLS_SERVICE_NAME: github
- name: Coverage - Push
if: matrix.TYPE == 'server' && github.event_name == 'push'
run: |
cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
cd ${GITHUB_WORKSPACE}
pip install coveralls==2.2.0
pip install coverage==4.5.4
coveralls --service=github-actions
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
COVERALLS_SERVICE_NAME: github-actions
COVERALLS_FLAG_NAME: run-${{ matrix.container }}
COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
COVERALLS_PARALLEL: true
coveralls:
name: Coverage Wrap Up
needs: test
container: python:3-slim
runs-on: ubuntu-18.04
steps:
- name: Clone
uses: actions/checkout@v2
- name: Coveralls Finished
run: |
cd ${GITHUB_WORKSPACE}
pip3 install coverage==5.5
pip3 install coveralls==3.0.1
coveralls --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

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)
@@ -27,7 +27,7 @@ class AccountingDimension(Document):
exists = frappe.db.get_value("Accounting Dimension", {'document_type': self.document_type}, ['name'])
if exists and self.is_new():
frappe.throw("Document Type already used as a dimension")
frappe.throw(_("Document Type already used as a dimension"))
if not self.is_new():
self.validate_document_type_change()

View File

@@ -7,7 +7,8 @@ import frappe
import unittest
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import delete_accounting_dimension
test_dependencies = ['Cost Center', 'Location', 'Warehouse', 'Department']
class TestAccountingDimension(unittest.TestCase):
def setUp(self):

View File

@@ -9,6 +9,8 @@ from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sal
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
test_dependencies = ['Location', 'Cost Center', 'Department']
class TestAccountingDimensionFilter(unittest.TestCase):
def setUp(self):
create_dimension()

View File

@@ -10,6 +10,8 @@ from erpnext.accounts.general_ledger import ClosedAccountingPeriod
from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
test_dependencies = ['Item']
class TestAccountingPeriod(unittest.TestCase):
def test_overlap(self):
ap1 = create_accounting_period(start_date = "2018-04-01",
@@ -38,7 +40,7 @@ def create_accounting_period(**args):
accounting_period.start_date = args.start_date or nowdate()
accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
accounting_period.company = args.company or "_Test Company"
accounting_period.period_name =args.period_name or "_Test_Period_Name_1"
accounting_period.period_name = args.period_name or "_Test_Period_Name_1"
accounting_period.append("closed_documents", {
"document_type": 'Sales Invoice', "closed": 1
})

View File

@@ -18,6 +18,8 @@
"delete_linked_ledger_entries",
"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",
@@ -253,6 +255,20 @@
{
"fieldname": "column_break_19",
"fieldtype": "Column Break"
},
{
"default": "1",
"description": "If enabled, ledger entries will be posted for change amount in POS transactions",
"fieldname": "post_change_gl_entries",
"fieldtype": "Check",
"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",
@@ -260,7 +276,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-04-30 15:25:10.381008",
"modified": "2021-07-12 18:54:29.084958",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",

View File

@@ -5,6 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint
from frappe.model.document import Document
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
@@ -20,11 +21,12 @@ 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:
frappe.msgprint(
"Stale Days should start from 1.", title='Error', indicator='red',
_("Stale Days should start from 1."), title='Error', indicator='red',
raise_exception=1)
def enable_payment_schedule_in_print(self):
@@ -32,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

@@ -0,0 +1,197 @@
{
"actions": [],
"creation": "2020-09-12 22:26:19.594367",
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"add_deduct_tax",
"charge_type",
"row_id",
"account_head",
"col_break_1",
"description",
"included_in_paid_amount",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"section_break_8",
"rate",
"section_break_9",
"currency",
"tax_amount",
"total",
"allocated_amount",
"column_break_13",
"base_tax_amount",
"base_total",
"base_allocated_amount"
],
"fields": [
{
"columns": 2,
"fieldname": "charge_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Type",
"oldfieldname": "charge_type",
"oldfieldtype": "Select",
"options": "\nActual\nOn Paid Amount\nOn Previous Row Amount\nOn Previous Row Total",
"reqd": 1
},
{
"depends_on": "eval:[\"On Previous Row Amount\", \"On Previous Row Total\"].indexOf(doc.charge_type)!==-1",
"fieldname": "row_id",
"fieldtype": "Data",
"label": "Reference Row #",
"oldfieldname": "row_id",
"oldfieldtype": "Data"
},
{
"columns": 2,
"fieldname": "account_head",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account Head",
"oldfieldname": "account_head",
"oldfieldtype": "Link",
"options": "Account",
"reqd": 1,
"search_index": 1
},
{
"fieldname": "col_break_1",
"fieldtype": "Column Break",
"width": "50%"
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"print_width": "300px",
"reqd": 1,
"width": "300px"
},
{
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
"label": "Accounting Dimensions"
},
{
"default": ":Company",
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
"oldfieldname": "cost_center_other_charges",
"oldfieldtype": "Link",
"options": "Cost Center"
},
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_8",
"fieldtype": "Section Break"
},
{
"columns": 2,
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency"
},
{
"fieldname": "section_break_9",
"fieldtype": "Section Break"
},
{
"columns": 2,
"fieldname": "tax_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"options": "currency"
},
{
"columns": 2,
"fieldname": "total",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Total",
"options": "currency",
"read_only": 1
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"fieldname": "base_tax_amount",
"fieldtype": "Currency",
"label": "Amount (Company Currency)",
"oldfieldname": "tax_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "base_total",
"fieldtype": "Currency",
"label": "Total (Company Currency)",
"oldfieldname": "total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "add_deduct_tax",
"fieldtype": "Select",
"label": "Add Or Deduct",
"options": "Add\nDeduct",
"reqd": 1
},
{
"default": "0",
"fieldname": "included_in_paid_amount",
"fieldtype": "Check",
"label": "Considered In Paid Amount"
},
{
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount",
"options": "currency"
},
{
"fieldname": "base_allocated_amount",
"fieldtype": "Currency",
"label": "Allocated Amount (Company Currency)",
"options": "Company:company:default_currency"
},
{
"fetch_from": "account_head.account_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-06-09 11:46:58.373170",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Advance Taxes and Charges",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "ASC"
}

View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class AdvanceTaxesandCharges(Document):
pass

View File

@@ -120,4 +120,4 @@ erpnext.integrations.refreshPlaidLink = class refreshPlaidLink {
plaid_success(token, response) {
frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
}
};
};

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

@@ -11,6 +11,8 @@ from erpnext.buying.doctype.purchase_order.test_purchase_order import create_pur
from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
test_dependencies = ['Monthly Distribution']
class TestBudget(unittest.TestCase):
def test_monthly_budget_crossed_ignore(self):
set_total_expense_zero(nowdate(), "cost_center")
@@ -247,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"
@@ -273,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):
@@ -22,7 +23,7 @@ def validate_company(company):
'allow_account_creation_against_child_company'])
if parent_company and (not allow_account_creation_against_child_company):
msg = _("{} is a child company. ").format(frappe.bold(company))
msg = _("{} is a child company.").format(frappe.bold(company)) + " "
msg += _("Please import accounts against parent company or enable {} in company master.").format(
frappe.bold('Allow Account Creation Against Child Company'))
frappe.throw(msg, title=_('Wrong Company'))
@@ -56,7 +57,7 @@ def get_file(file_name):
extension = extension.lstrip(".")
if extension not in ('csv', 'xlsx', 'xls'):
frappe.throw("Only CSV and Excel files can be used to for importing data. Please check the file format you are trying to upload")
frappe.throw(_("Only CSV and Excel files can be used to for importing data. Please check the file format you are trying to upload"))
return file_doc, extension
@@ -293,7 +294,7 @@ def validate_accounts(file_name):
accounts_dict = {}
for account in accounts:
accounts_dict.setdefault(account["account_name"], account)
if not hasattr(account, "parent_account"):
if "parent_account" not in account:
msg = _("Please make sure the file you are using has 'Parent Account' column present in the header.")
msg += "<br><br>"
msg += _("Alternatively, you can download the template and fill your data in.")
@@ -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,18 +42,18 @@ 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()
self.make_gl_entries()
def on_cancel(self):
self.set_status()
self.set_status(cancel=1)
self.update_sales_invoice()
self.make_gl_entries()
def set_status(self, status=None):
def set_status(self, status=None, cancel=0):
if status:
self.status = status
self.db_set("status", status)
@@ -66,6 +66,9 @@ class InvoiceDiscounting(AccountsController):
elif self.docstatus == 2:
self.status = "Cancelled"
if cancel:
self.db_set('status', self.status, update_modified = True)
def update_sales_invoice(self):
for d in self.invoices:
if self.docstatus == 1:

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

@@ -0,0 +1,17 @@
frappe.ui.form.on("Journal Entry", {
refresh: function(frm) {
frm.set_query('company_address', function(doc) {
if(!doc.company) {
frappe.throw(__('Please set Company'));
}
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
link_doctype: 'Company',
link_name: doc.company
}
};
});
}
});

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

@@ -3,8 +3,12 @@
{% include "erpnext/public/js/controllers/accounts.js" %}
frappe.provide("erpnext.accounts.dimensions");
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);
@@ -91,6 +95,16 @@ frappe.ui.form.on('Payment Entry', {
}
});
frm.set_query("advance_tax_account", function() {
return {
filters: {
"company": frm.doc.company,
"root_type": ["in", ["Asset", "Liability"]],
"is_group": 0
}
}
});
frm.set_query("reference_doctype", "references", function() {
if (frm.doc.party_type == "Customer") {
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
@@ -182,6 +196,8 @@ frappe.ui.form.on('Payment Entry', {
frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency));
frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
(frm.doc.paid_from_account_currency != company_currency));
frm.toggle_display("base_received_amount", (
frm.doc.paid_to_account_currency != company_currency
@@ -216,7 +232,7 @@ frappe.ui.form.on('Payment Entry', {
var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: "";
frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
"difference_amount"], company_currency);
"difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency);
frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency);
frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency);
@@ -224,11 +240,13 @@ frappe.ui.form.on('Payment Entry', {
var party_account_currency = frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency;
frm.set_currency_labels(["total_allocated_amount", "unallocated_amount"], party_account_currency);
frm.set_currency_labels(["total_allocated_amount", "unallocated_amount",
"total_taxes_and_charges"], party_account_currency);
var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency"
frm.set_df_property("total_allocated_amount", "options", currency_field);
frm.set_df_property("unallocated_amount", "options", currency_field);
frm.set_df_property("total_taxes_and_charges", "options", currency_field);
frm.set_df_property("party_balance", "options", currency_field);
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
@@ -364,6 +382,16 @@ frappe.ui.form.on('Payment Entry', {
}
},
apply_tax_withholding_amount: function(frm) {
if (!frm.doc.apply_tax_withholding_amount) {
frm.set_value("tax_withholding_category", '');
} else {
frappe.db.get_value('Supplier', frm.doc.party, 'tax_withholding_category', (values) => {
frm.set_value("tax_withholding_category", values.tax_withholding_category);
});
}
},
paid_from: function(frm) {
if(frm.set_party_account_based_on_party) return;
@@ -843,12 +871,12 @@ frappe.ui.form.on('Payment Entry', {
if(frm.doc.payment_type == "Receive"
&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
unallocated_amount = (frm.doc.base_received_amount + total_deductions
- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
unallocated_amount = (frm.doc.base_received_amount + total_deductions + frm.doc.base_total_taxes_and_charges
+ frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
} else if (frm.doc.payment_type == "Pay"
&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions
&& frm.doc.total_allocated_amount < frm.doc.received_amount + (total_deductions / frm.doc.target_exchange_rate)) {
unallocated_amount = (frm.doc.base_paid_amount - (total_deductions
unallocated_amount = (frm.doc.base_paid_amount + frm.doc.base_total_taxes_and_charges - (total_deductions
+ frm.doc.base_total_allocated_amount)) / frm.doc.target_exchange_rate;
}
}
@@ -874,7 +902,8 @@ frappe.ui.form.on('Payment Entry', {
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
function(d) { return flt(d.amount) }));
frm.set_value("difference_amount", difference_amount - total_deductions);
frm.set_value("difference_amount", difference_amount - total_deductions +
frm.doc.base_total_taxes_and_charges);
frm.events.hide_unhide_fields(frm);
},
@@ -1002,7 +1031,266 @@ frappe.ui.form.on('Payment Entry', {
}
});
}
}
},
sales_taxes_and_charges_template: function(frm) {
frm.trigger('fetch_taxes_from_template');
},
purchase_taxes_and_charges_template: function(frm) {
frm.trigger('fetch_taxes_from_template');
},
fetch_taxes_from_template: function(frm) {
let master_doctype = '';
let taxes_and_charges = '';
if (frm.doc.party_type == 'Supplier') {
master_doctype = 'Purchase Taxes and Charges Template';
taxes_and_charges = frm.doc.purchase_taxes_and_charges_template;
} else if (frm.doc.party_type == 'Customer') {
master_doctype = 'Sales Taxes and Charges Template';
taxes_and_charges = frm.doc.sales_taxes_and_charges_template;
}
if (!taxes_and_charges) {
return;
}
frappe.call({
method: "erpnext.controllers.accounts_controller.get_taxes_and_charges",
args: {
"master_doctype": master_doctype,
"master_name": taxes_and_charges
},
callback: function(r) {
if(!r.exc && r.message) {
// set taxes table
if(r.message) {
for (let tax of r.message) {
if (tax.charge_type === 'On Net Total') {
tax.charge_type = 'On Paid Amount';
}
me.frm.add_child("taxes", tax);
}
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
}
}
}
});
},
apply_taxes: function(frm) {
frm.events.initialize_taxes(frm);
frm.events.determine_exclusive_rate(frm);
frm.events.calculate_taxes(frm);
},
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"];
if (cstr(tax.charge_type) != "Actual") {
tax_fields.push("tax_amount");
}
$.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0; });
frm.doc.paid_amount_after_tax = frm.doc.paid_amount;
});
},
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) {
if(cint(row.included_in_paid_amount)) has_inclusive_tax = true;
});
if(has_inclusive_tax==false) return;
let cumulated_tax_fraction = 0.0;
$.each(frm.doc["taxes"] || [], function(i, tax) {
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;
} else {
tax.grand_total_fraction_for_current_item =
me.frm.doc["taxes"][i-1].grand_total_fraction_for_current_item +
tax.tax_fraction_for_current_item;
}
cumulated_tax_fraction += tax.tax_fraction_for_current_item;
frm.doc.paid_amount_after_tax = flt(frm.doc.paid_amount/(1+cumulated_tax_fraction))
});
},
get_current_tax_fraction: function(frm, tax) {
let current_tax_fraction = 0.0;
if(cint(tax.included_in_paid_amount)) {
let tax_rate = tax.rate;
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) *
frm.doc["taxes"][cint(tax.row_id) - 1].tax_fraction_for_current_item;
} else if(tax.charge_type == "On Previous Row Total") {
current_tax_fraction = (tax_rate / 100.0) *
frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
}
}
if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") {
current_tax_fraction *= -1;
}
return current_tax_fraction;
},
calculate_taxes: function(frm) {
frm.doc.total_taxes_and_charges = 0.0;
frm.doc.base_total_taxes_and_charges = 0.0;
let actual_tax_dict = {};
// maintain actual tax rate based on idx
$.each(frm.doc["taxes"] || [], function(i, tax) {
if (tax.charge_type == "Actual") {
actual_tax_dict[tax.idx] = flt(tax.tax_amount, precision("tax_amount", tax));
}
});
$.each(me.frm.doc["taxes"] || [], function(i, tax) {
let current_tax_amount = frm.events.get_current_tax_amount(frm, tax);
// Adjust divisional loss to the last item
if (tax.charge_type == "Actual") {
actual_tax_dict[tax.idx] -= current_tax_amount;
if (i == frm.doc["taxes"].length - 1) {
current_tax_amount += actual_tax_dict[tax.idx];
}
}
tax.tax_amount = current_tax_amount;
tax.base_tax_amount = tax.tax_amount * frm.doc.source_exchange_rate;
current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
if(i==0) {
tax.total = flt(frm.doc.paid_amount_after_tax + current_tax_amount, precision("total", tax));
} else {
tax.total = flt(frm.doc["taxes"][i-1].total + current_tax_amount, precision("total", tax));
}
tax.base_total = tax.total * frm.doc.source_exchange_rate;
frm.doc.total_taxes_and_charges += current_tax_amount;
frm.doc.base_total_taxes_and_charges += current_tax_amount * frm.doc.source_exchange_rate;
frm.refresh_field('taxes');
frm.refresh_field('total_taxes_and_charges');
frm.refresh_field('base_total_taxes_and_charges');
});
},
get_current_tax_amount: function(frm, tax) {
let tax_rate = tax.rate;
let current_tax_amount = 0.0;
// To set row_id by default as previous row.
if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
if (tax.idx === 1) {
frappe.throw(
__("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"));
}
}
if(tax.charge_type == "Actual") {
current_tax_amount = flt(tax.tax_amount, precision("tax_amount", tax))
} else if(tax.charge_type == "On Paid Amount") {
current_tax_amount = flt((tax_rate / 100.0) * frm.doc.paid_amount_after_tax);
} else if(tax.charge_type == "On Previous Row Amount") {
current_tax_amount = flt((tax_rate / 100.0) *
frm.doc["taxes"][cint(tax.row_id) - 1].tax_amount);
} else if(tax.charge_type == "On Previous Row Total") {
current_tax_amount = flt((tax_rate / 100.0) *
frm.doc["taxes"][cint(tax.row_id) - 1].total);
}
return current_tax_amount;
},
});
@@ -1049,6 +1337,38 @@ frappe.ui.form.on('Payment Entry Reference', {
}
})
frappe.ui.form.on('Advance Taxes and Charges', {
rate: function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
},
tax_amount : function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
},
row_id: function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
},
taxes_remove: function(frm) {
frm.events.apply_taxes(frm);
frm.events.set_unallocated_amount(frm);
},
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);
}
})
frappe.ui.form.on('Payment Entry Deduction', {
amount: function(frm) {
frm.events.set_unallocated_amount(frm);

View File

@@ -35,12 +35,16 @@
"paid_to_account_balance",
"payment_amounts_section",
"paid_amount",
"paid_amount_after_tax",
"source_exchange_rate",
"base_paid_amount",
"base_paid_amount_after_tax",
"column_break_21",
"received_amount",
"received_amount_after_tax",
"target_exchange_rate",
"base_received_amount",
"base_received_amount_after_tax",
"section_break_14",
"get_outstanding_invoice",
"references",
@@ -52,6 +56,17 @@
"unallocated_amount",
"difference_amount",
"write_off_difference_amount",
"taxes_and_charges_section",
"purchase_taxes_and_charges_template",
"sales_taxes_and_charges_template",
"advance_tax_account",
"column_break_55",
"apply_tax_withholding_amount",
"tax_withholding_category",
"section_break_56",
"taxes",
"base_total_taxes_and_charges",
"total_taxes_and_charges",
"deductions_or_loss_section",
"deductions",
"transaction_references",
@@ -320,6 +335,7 @@
"reqd": 1
},
{
"depends_on": "doc.received_amount",
"fieldname": "base_received_amount",
"fieldtype": "Currency",
"label": "Received Amount (Company Currency)",
@@ -584,12 +600,119 @@
"fieldname": "custom_remarks",
"fieldtype": "Check",
"label": "Custom Remarks"
},
{
"depends_on": "eval:doc.apply_tax_withholding_amount",
"fieldname": "tax_withholding_category",
"fieldtype": "Link",
"label": "Tax Withholding Category",
"mandatory_depends_on": "eval:doc.apply_tax_withholding_amount",
"options": "Tax Withholding Category"
},
{
"default": "0",
"depends_on": "eval:doc.party_type == 'Supplier'",
"fieldname": "apply_tax_withholding_amount",
"fieldtype": "Check",
"label": "Apply Tax Withholding Amount"
},
{
"collapsible": 1,
"fieldname": "taxes_and_charges_section",
"fieldtype": "Section Break",
"label": "Taxes and Charges"
},
{
"depends_on": "eval:doc.party_type == 'Supplier'",
"fieldname": "purchase_taxes_and_charges_template",
"fieldtype": "Link",
"label": "Taxes and Charges Template",
"options": "Purchase Taxes and Charges Template"
},
{
"depends_on": "eval: doc.party_type == 'Customer'",
"fieldname": "sales_taxes_and_charges_template",
"fieldtype": "Link",
"label": "Taxes and Charges Template",
"options": "Sales Taxes and Charges Template"
},
{
"depends_on": "eval: doc.party_type == 'Supplier' || doc.party_type == 'Customer'",
"fieldname": "taxes",
"fieldtype": "Table",
"label": "Advance Taxes and Charges",
"options": "Advance Taxes and Charges"
},
{
"fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency",
"label": "Total Taxes and Charges (Company Currency)",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
"label": "Total Taxes and Charges",
"read_only": 1
},
{
"fieldname": "paid_amount_after_tax",
"fieldtype": "Currency",
"hidden": 1,
"label": "Paid Amount After Tax",
"options": "paid_from_account_currency",
"read_only": 1
},
{
"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
},
{
"fieldname": "column_break_55",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_56",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"depends_on": "eval:doc.apply_tax_withholding_amount",
"description": "Provisional tax account for advance tax. Taxes are parked in this account until payments are allocated to invoices",
"fieldname": "advance_tax_account",
"fieldtype": "Link",
"label": "Advance Tax Account",
"mandatory_depends_on": "eval:doc.apply_tax_withholding_amount",
"options": "Account"
},
{
"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",
"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",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-03-08 13:05:16.958866",
"modified": "2021-07-09 08:58:15.008761",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@@ -633,4 +756,4 @@
"sort_order": "DESC",
"title_field": "title",
"track_changes": 1
}
}

View File

@@ -4,8 +4,8 @@
from __future__ import unicode_literals
import frappe, erpnext, json
from frappe import _, scrub, ValidationError
from frappe.utils import flt, comma_or, nowdate, getdate
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
from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
@@ -15,9 +15,11 @@ from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo
from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details
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
@@ -52,6 +54,8 @@ class PaymentEntry(AccountsController):
self.set_exchange_rate()
self.validate_mandatory()
self.validate_reference_documents()
self.set_tax_withholding()
self.apply_taxes()
self.set_amounts()
self.clear_unallocated_reference_document_rows()
self.validate_payment_against_negative_invoice()
@@ -65,7 +69,6 @@ class PaymentEntry(AccountsController):
self.set_status()
def on_submit(self):
self.setup_party_account_field()
if self.difference_amount:
frappe.throw(_("Difference Amount must be zero"))
self.make_gl_entries()
@@ -78,7 +81,6 @@ class PaymentEntry(AccountsController):
def on_cancel(self):
self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry')
self.setup_party_account_field()
self.make_gl_entries(cancel=1)
self.update_outstanding_amounts()
self.update_advance_paid()
@@ -122,6 +124,11 @@ class PaymentEntry(AccountsController):
if flt(d.allocated_amount) > flt(d.outstanding_amount):
frappe.throw(_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx))
# Check for negative outstanding invoices as well
if flt(d.allocated_amount) < 0:
if flt(d.allocated_amount) < flt(d.outstanding_amount):
frappe.throw(_("Row #{0}: Allocated Amount cannot be greater than outstanding amount.").format(d.idx))
def delink_advance_entry_references(self):
for reference in self.references:
if reference.reference_doctype in ("Sales Invoice", "Purchase Invoice"):
@@ -176,8 +183,15 @@ 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.set(field, value)
d.db_set(field, value)
def validate_payment_type(self):
if self.payment_type not in ("Receive", "Pay", "Internal Transfer"):
@@ -303,11 +317,10 @@ 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")
def validate_journal_entry(self):
for d in self.get("references"):
if d.allocated_amount and d.reference_doctype == "Journal Entry":
@@ -386,12 +399,104 @@ class PaymentEntry(AccountsController):
else:
self.status = 'Draft'
self.db_set('status', self.status, update_modified = True)
def set_tax_withholding(self):
if not self.party_type == 'Supplier':
return
if not self.apply_tax_withholding_amount:
return
if not self.advance_tax_account:
frappe.throw(_("Advance TDS account is mandatory for advance TDS deduction"))
net_total = self.paid_amount
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({
'company': self.company,
'doctype': 'Purchase Invoice',
'supplier': self.party,
'posting_date': self.posting_date,
'net_total': net_total
})
tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category)
if not tax_withholding_details:
return
tax_withholding_details.update({
'add_deduct_tax': 'Add',
'cost_center': self.cost_center or erpnext.get_default_cost_center(self.company)
})
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
# Preserve user updated included in paid amount
if d.included_in_paid_amount:
tax_withholding_details.update({'included_in_paid_amount': d.included_in_paid_amount})
d.update(tax_withholding_details)
accounts.append(d.account_head)
if not accounts or tax_withholding_details.get("account_head") not in accounts:
self.append("taxes", tax_withholding_details)
to_remove = [d for d in self.taxes
if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
for d in to_remove:
self.remove(d)
def apply_taxes(self):
self.initialize_taxes()
self.determine_exclusive_rate()
self.calculate_taxes()
def set_amounts(self):
self.set_received_amount()
self.set_amounts_in_company_currency()
self.set_amounts_after_tax()
self.set_total_allocated_amount()
self.set_unallocated_amount()
self.set_difference_amount()
def set_received_amount(self):
self.base_received_amount = self.base_paid_amount
def set_amounts_after_tax(self):
applicable_tax = 0
base_applicable_tax = 0
for tax in self.get('taxes'):
if not tax.included_in_paid_amount:
amount = -1 * tax.tax_amount if tax.add_deduct_tax == 'Deduct' else tax.tax_amount
base_amount = -1 * tax.base_tax_amount if tax.add_deduct_tax == 'Deduct' else tax.base_tax_amount
applicable_tax += amount
base_applicable_tax += base_amount
self.paid_amount_after_tax = flt(flt(self.paid_amount) + flt(applicable_tax),
self.precision("paid_amount_after_tax"))
self.base_paid_amount_after_tax = flt(flt(self.paid_amount_after_tax) * flt(self.source_exchange_rate),
self.precision("base_paid_amount_after_tax"))
self.received_amount_after_tax = flt(flt(self.received_amount) + flt(applicable_tax),
self.precision("paid_amount_after_tax"))
self.base_received_amount_after_tax = flt(flt(self.received_amount_after_tax) * flt(self.target_exchange_rate),
self.precision("base_paid_amount_after_tax"))
def set_amounts_in_company_currency(self):
self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0
if self.paid_amount:
@@ -419,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 + total_deductions \
and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
self.unallocated_amount = (self.base_received_amount + total_deductions -
self.base_total_allocated_amount) / 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 - 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 = (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)
@@ -444,11 +552,23 @@ class PaymentEntry(AccountsController):
else:
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):
@@ -460,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])
@@ -532,6 +652,7 @@ class PaymentEntry(AccountsController):
self.add_party_gl_entries(gl_entries)
self.add_bank_gl_entries(gl_entries)
self.add_deductions_gl_entries(gl_entries)
self.add_tax_gl_entries(gl_entries)
make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
@@ -571,8 +692,8 @@ class PaymentEntry(AccountsController):
gl_entries.append(gle)
if self.unallocated_amount:
base_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()
@@ -607,6 +728,51 @@ class PaymentEntry(AccountsController):
}, item=self)
)
def add_tax_gl_entries(self, gl_entries):
for d in self.get('taxes'):
account_currency = get_account_currency(d.account_head)
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 in ('Pay', 'Internal Transfer'):
dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit"
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": 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
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"):
if d.amount:
@@ -625,6 +791,14 @@ class PaymentEntry(AccountsController):
}, item=d)
)
def get_party_account_for_taxes(self):
if self.advance_tax_account:
return self.advance_tax_account
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:
for d in self.get("references"):
@@ -667,10 +841,150 @@ 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":
tax_fields.append("tax_amount")
for fieldname in tax_fields:
tax.set(fieldname, 0.0)
self.paid_amount_after_tax = self.paid_amount
def determine_exclusive_rate(self):
if not any((cint(tax.included_in_paid_amount) for tax in self.get("taxes"))):
return
cumulated_tax_fraction = 0
for i, tax in enumerate(self.get("taxes")):
tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax)
if i==0:
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
else:
tax.grand_total_fraction_for_current_item = \
self.get("taxes")[i-1].grand_total_fraction_for_current_item \
+ tax.tax_fraction_for_current_item
cumulated_tax_fraction += tax.tax_fraction_for_current_item
self.paid_amount_after_tax = flt(self.paid_amount/(1+cumulated_tax_fraction))
def calculate_taxes(self):
self.total_taxes_and_charges = 0.0
self.base_total_taxes_and_charges = 0.0
actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
for tax in self.get("taxes") if tax.charge_type == "Actual"])
for i, tax in enumerate(self.get('taxes')):
current_tax_amount = self.get_current_tax_amount(tax)
if tax.charge_type == "Actual":
actual_tax_dict[tax.idx] -= current_tax_amount
if i == len(self.get("taxes")) - 1:
current_tax_amount += actual_tax_dict[tax.idx]
tax.tax_amount = current_tax_amount
tax.base_tax_amount = tax.tax_amount * self.source_exchange_rate
if tax.add_deduct_tax == "Deduct":
current_tax_amount *= -1.0
else:
current_tax_amount *= 1.0
if i == 0:
tax.total = flt(self.paid_amount_after_tax + current_tax_amount, self.precision("total", tax))
else:
tax.total = flt(self.get('taxes')[i-1].total + current_tax_amount, self.precision("total", tax))
tax.base_total = tax.total * self.source_exchange_rate
self.total_taxes_and_charges += current_tax_amount
self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate
if self.get('taxes'):
self.paid_amount_after_tax = self.get('taxes')[-1].base_total
def get_current_tax_amount(self, tax):
tax_rate = tax.rate
# To set row_id by default as previous row.
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"]:
if tax.idx == 1:
frappe.throw(_("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"))
if not tax.row_id:
tax.row_id = tax.idx - 1
if tax.charge_type == "Actual":
current_tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax))
elif tax.charge_type == "On Paid Amount":
current_tax_amount = (tax_rate / 100.0) * self.paid_amount_after_tax
elif tax.charge_type == "On Previous Row Amount":
current_tax_amount = (tax_rate / 100.0) * \
self.get('taxes')[cint(tax.row_id) - 1].tax_amount
elif tax.charge_type == "On Previous Row Total":
current_tax_amount = (tax_rate / 100.0) * \
self.get('taxes')[cint(tax.row_id) - 1].total
return current_tax_amount
def get_current_tax_fraction(self, tax):
current_tax_fraction = 0
if cint(tax.included_in_paid_amount):
tax_rate = tax.rate
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
if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct":
current_tax_fraction *= -1.0
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):
@@ -791,7 +1105,7 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
outstanding_invoices.pop(idx - 1)
outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
return outstanding_invoices
def get_orders_to_be_billed(posting_date, party_type, party,
@@ -989,6 +1303,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
outstanding_amount = ref_doc.get("outstanding_amount")
elif reference_doctype == "Donation":
total_amount = ref_doc.get("amount")
outstanding_amount = total_amount
exchange_rate = 1
elif reference_doctype == "Dunning":
total_amount = ref_doc.get("dunning_amount")
@@ -1045,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
})
@@ -1235,6 +1550,13 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
})
pe.set_difference_amount()
if doc.doctype == 'Purchase Order' and doc.apply_tds:
pe.apply_tax_withholding_amount = 1
pe.tax_withholding_category = doc.tax_withholding_category
if not pe.advance_tax_account:
pe.advance_tax_account = frappe.db.get_value('Company', pe.company, 'unrealized_profit_loss_account')
return pe
def get_bank_cash_account(doc, bank_account):
@@ -1353,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

@@ -1,140 +1,70 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2016-06-15 15:56:30.815503",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"actions": [],
"creation": "2016-06-15 15:56:30.815503",
"doctype": "DocType",
"editable_grid": 1,
"field_order": [
"account",
"cost_center",
"amount",
"column_break_2",
"description"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account",
"fieldtype": "Link",
"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": "Account",
"length": 0,
"no_copy": 0,
"options": "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": "account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Account",
"options": "Account",
"reqd": 1,
"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": "cost_center",
"fieldtype": "Link",
"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": "Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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": "cost_center",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Cost Center",
"options": "Cost Center",
"print_hide": 1,
"reqd": 1,
"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": "amount",
"fieldtype": "Currency",
"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": "Amount",
"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": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description",
"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": 1,
"max_attachments": 0,
"modified": "2019-01-07 16:52:07.040146",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Deduction",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2020-09-12 20:38:08.110674",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Deduction",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

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

@@ -101,7 +101,7 @@ class PaymentRequest(Document):
controller.validate_transaction_currency(self.currency)
controller.request_for_payment(**payment_record)
def get_request_amount(self):
data_of_completed_requests = frappe.get_all("Integration Request", filters={
'reference_doctype': self.doctype,
@@ -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):
@@ -492,7 +492,6 @@ def update_payment_req_status(doc, method):
status = 'Requested'
pay_req_doc.db_set('status', status)
frappe.db.commit()
def get_dummy_message(doc):
return frappe.render_template("""{% if doc.contact_person -%}

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

@@ -1,350 +1,138 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "ACC-PCV-.YYYY.-.#####",
"beta": 0,
"creation": "2013-01-10 16:34:07",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 0,
"engine": "InnoDB",
"actions": [],
"autoname": "ACC-PCV-.YYYY.-.#####",
"creation": "2013-01-10 16:34:07",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"transaction_date",
"posting_date",
"fiscal_year",
"amended_from",
"company",
"cost_center_wise_pnl",
"column_break1",
"closing_account_head",
"remarks"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "transaction_date",
"fieldtype": "Date",
"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": "Transaction Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "transaction_date",
"oldfieldtype": "Date",
"permlevel": 0,
"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
},
"fieldname": "transaction_date",
"fieldtype": "Date",
"label": "Transaction Date",
"oldfieldname": "transaction_date",
"oldfieldtype": "Date"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "posting_date",
"fieldtype": "Date",
"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": "Posting Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"permlevel": 0,
"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": "posting_date",
"fieldtype": "Date",
"label": "Posting Date",
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fiscal_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Closing Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"permlevel": 0,
"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": "fiscal_year",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Closing Fiscal Year",
"oldfieldname": "fiscal_year",
"oldfieldtype": "Select",
"options": "Fiscal Year",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Period Closing Voucher",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Amended From",
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Period Closing Voucher",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"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": "Company",
"length": 0,
"no_copy": 0,
"oldfieldname": "company",
"oldfieldtype": "Select",
"options": "Company",
"permlevel": 0,
"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": "company",
"fieldtype": "Link",
"label": "Company",
"oldfieldname": "company",
"oldfieldtype": "Select",
"options": "Company",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break1",
"fieldtype": "Column 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,
"length": 0,
"no_copy": 0,
"oldfieldtype": "Column Break",
"permlevel": 0,
"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
},
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "The account head under Liability or Equity, in which Profit/Loss will be booked",
"fieldname": "closing_account_head",
"fieldtype": "Link",
"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": "Closing Account Head",
"length": 0,
"no_copy": 0,
"oldfieldname": "closing_account_head",
"oldfieldtype": "Link",
"options": "Account",
"permlevel": 0,
"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
},
"description": "The account head under Liability or Equity, in which Profit/Loss will be booked",
"fieldname": "closing_account_head",
"fieldtype": "Link",
"label": "Closing Account Head",
"oldfieldname": "closing_account_head",
"oldfieldtype": "Link",
"options": "Account",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "remarks",
"fieldtype": "Small Text",
"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": "Remarks",
"length": 0,
"no_copy": 0,
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"permlevel": 0,
"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": "remarks",
"fieldtype": "Small Text",
"label": "Remarks",
"oldfieldname": "remarks",
"oldfieldtype": "Small Text",
"reqd": 1
},
{
"default": "0",
"fieldname": "cost_center_wise_pnl",
"fieldtype": "Check",
"label": "Book Cost Center Wise Profit/Loss"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-file-text",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2020-09-18 17:26:09.703215",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Period Closing Voucher",
"owner": "Administrator",
],
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-05-20 15:27:37.210458",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Period Closing Voucher",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 1,
"write": 1
},
},
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "posting_date, fiscal_year",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "closing_account_head",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
],
"search_fields": "posting_date, fiscal_year",
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "closing_account_head"
}

View File

@@ -51,63 +51,96 @@ class PeriodClosingVoucher(AccountsController):
def make_gl_entries(self):
gl_entries = []
net_pl_balance = 0
dimension_fields = ['t1.cost_center']
net_pl_balance = 0
accounting_dimensions = get_accounting_dimensions()
for dimension in accounting_dimensions:
dimension_fields.append('t1.{0}'.format(dimension))
dimension_filters, default_dimensions = get_dimensions()
pl_accounts = self.get_pl_balances(dimension_fields)
pl_accounts = self.get_pl_balances()
for acc in pl_accounts:
if flt(acc.balance_in_company_currency):
if flt(acc.bal_in_company_currency):
gl_entries.append(self.get_gl_dict({
"account": acc.account,
"cost_center": acc.cost_center,
"account_currency": acc.account_currency,
"debit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
if flt(acc.balance_in_account_currency) < 0 else 0,
"debit": abs(flt(acc.balance_in_company_currency)) \
if flt(acc.balance_in_company_currency) < 0 else 0,
"credit_in_account_currency": abs(flt(acc.balance_in_account_currency)) \
if flt(acc.balance_in_account_currency) > 0 else 0,
"credit": abs(flt(acc.balance_in_company_currency)) \
if flt(acc.balance_in_company_currency) > 0 else 0
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
}, item=acc))
net_pl_balance += flt(acc.balance_in_company_currency)
net_pl_balance += flt(acc.bal_in_company_currency)
if net_pl_balance:
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
gl_entry = self.get_gl_dict({
"account": self.closing_account_head,
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"cost_center": cost_center
})
for dimension in accounting_dimensions:
gl_entry.update({
dimension: default_dimensions.get(self.company, {}).get(dimension)
})
gl_entries.append(gl_entry)
if self.cost_center_wise_pnl:
costcenter_wise_gl_entries = self.get_costcenter_wise_pnl_gl_entries(pl_accounts)
gl_entries += costcenter_wise_gl_entries
else:
gl_entry = self.get_pnl_gl_entry(net_pl_balance)
gl_entries.append(gl_entry)
from erpnext.accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries)
def get_pnl_gl_entry(self, net_pl_balance):
cost_center = frappe.db.get_value("Company", self.company, "cost_center")
gl_entry = self.get_gl_dict({
"account": self.closing_account_head,
"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
"cost_center": cost_center
})
self.update_default_dimensions(gl_entry)
return gl_entry
def get_costcenter_wise_pnl_gl_entries(self, pl_accounts):
company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
gl_entries = []
for acc in pl_accounts:
if flt(acc.bal_in_company_currency):
gl_entry = self.get_gl_dict({
"account": self.closing_account_head,
"cost_center": acc.cost_center or company_cost_center,
"account_currency": acc.account_currency,
"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
"credit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0
}, item=acc)
self.update_default_dimensions(gl_entry)
gl_entries.append(gl_entry)
return gl_entries
def update_default_dimensions(self, gl_entry):
if not self.accounting_dimensions:
self.accounting_dimensions = get_accounting_dimensions()
_, default_dimensions = get_dimensions()
for dimension in self.accounting_dimensions:
gl_entry.update({
dimension: default_dimensions.get(self.company, {}).get(dimension)
})
def get_pl_balances(self):
"""Get balance for dimension-wise pl accounts"""
dimension_fields = ['t1.cost_center']
self.accounting_dimensions = get_accounting_dimensions()
for dimension in self.accounting_dimensions:
dimension_fields.append('t1.{0}'.format(dimension))
def get_pl_balances(self, dimension_fields):
"""Get balance for pl accounts"""
return frappe.db.sql("""
select
t1.account, t2.account_currency, {dimension_fields},
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as balance_in_account_currency,
sum(t1.debit) - sum(t1.credit) as balance_in_company_currency
sum(t1.debit_in_account_currency) - sum(t1.credit_in_account_currency) as bal_in_account_currency,
sum(t1.debit) - sum(t1.credit) as bal_in_company_currency
from `tabGL Entry` t1, `tabAccount` t2
where t1.account = t2.name and t2.report_type = 'Profit and Loss'
and t2.docstatus < 2 and t2.company = %s

View File

@@ -8,6 +8,7 @@ import frappe
from frappe.utils import flt, today
from erpnext.accounts.utils import get_fiscal_year, now
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
class TestPeriodClosingVoucher(unittest.TestCase):
def test_closing_entry(self):
@@ -65,6 +66,58 @@ class TestPeriodClosingVoucher(unittest.TestCase):
self.assertEqual(gle_for_random_expense_account[0].amount_in_account_currency,
-1*random_expense_account[0].balance_in_account_currency)
def test_cost_center_wise_posting(self):
frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
company = create_company()
surplus_account = create_account()
cost_center1 = create_cost_center("Test Cost Center 1")
cost_center2 = create_cost_center("Test Cost Center 2")
create_sales_invoice(
company=company,
cost_center=cost_center1,
income_account="Sales - TPC",
expense_account="Cost of Goods Sold - TPC",
rate=400,
debit_to="Debtors - TPC"
)
create_sales_invoice(
company=company,
cost_center=cost_center2,
income_account="Sales - TPC",
expense_account="Cost of Goods Sold - TPC",
rate=200,
debit_to="Debtors - TPC"
)
pcv = frappe.get_doc({
"transaction_date": today(),
"posting_date": today(),
"fiscal_year": get_fiscal_year(today())[0],
"company": "Test PCV Company",
"cost_center_wise_pnl": 1,
"closing_account_head": surplus_account,
"remarks": "Test",
"doctype": "Period Closing Voucher"
})
pcv.insert()
pcv.submit()
expected_gle = (
('Sales - TPC', 200.0, 0.0, cost_center2),
(surplus_account, 0.0, 200.0, cost_center2),
('Sales - TPC', 400.0, 0.0, cost_center1),
(surplus_account, 0.0, 400.0, cost_center1)
)
pcv_gle = frappe.db.sql("""
select account, debit, credit, cost_center from `tabGL Entry` where voucher_no=%s
""", (pcv.name))
self.assertTrue(pcv_gle, expected_gle)
def make_period_closing_voucher(self):
pcv = frappe.get_doc({
"doctype": "Period Closing Voucher",
@@ -80,6 +133,38 @@ class TestPeriodClosingVoucher(unittest.TestCase):
return pcv
def create_company():
company = frappe.get_doc({
'doctype': 'Company',
'company_name': "Test PCV Company",
'country': 'United States',
'default_currency': 'USD'
})
company.insert(ignore_if_duplicate = True)
return company.name
def create_account():
account = frappe.get_doc({
"account_name": "Reserve and Surplus",
"is_group": 0,
"company": "Test PCV Company",
"root_type": "Liability",
"report_type": "Balance Sheet",
"account_currency": "USD",
"parent_account": "Current Liabilities - TPC",
"doctype": "Account"
}).insert(ignore_if_duplicate = True)
return account.name
def create_cost_center(cc_name):
costcenter = frappe.get_doc({
"company": "Test PCV Company",
"cost_center_name": cc_name,
"doctype": "Cost Center",
"parent_cost_center": "Test PCV Company - TPC"
})
costcenter.insert(ignore_if_duplicate = True)
return costcenter.name
test_dependencies = ["Customer", "Cost Center"]
test_records = frappe.get_test_records("Period Closing Voucher")

View File

@@ -107,7 +107,7 @@ frappe.ui.form.on('POS Closing Entry', {
frm.set_value("taxes", []);
for (let row of frm.doc.payment_reconciliation) {
row.expected_amount = 0;
row.expected_amount = row.opening_amount;
}
for (let row of frm.doc.pos_transactions) {
@@ -154,6 +154,9 @@ function add_to_pos_transaction(d, frm) {
function refresh_payments(d, frm) {
d.payments.forEach(p => {
const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment);
if (p.account == d.account_for_change_amount) {
p.amount -= flt(d.change_amount);
}
if (payment) {
payment.expected_amount += flt(p.amount);
payment.difference = payment.closing_amount - payment.expected_amount;

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

@@ -140,6 +140,7 @@ class POSInvoice(SalesInvoice):
return
available_stock = get_stock_availability(d.item_code, d.warehouse)
item_code, warehouse, qty = frappe.bold(d.item_code), frappe.bold(d.warehouse), frappe.bold(d.qty)
if flt(available_stock) <= 0:
frappe.throw(_('Row #{}: Item Code: {} is not available under warehouse {}.')
@@ -213,8 +214,9 @@ class POSInvoice(SalesInvoice):
for d in self.get("items"):
is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
if not is_stock_item:
frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ")
.format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item"))
if not frappe.db.exists('Product Bundle', d.item_code):
frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice.")
.format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item"))
def validate_mode_of_payment(self):
if len(self.payments) == 0:
@@ -455,15 +457,36 @@ class POSInvoice(SalesInvoice):
@frappe.whitelist()
def get_stock_availability(item_code, warehouse):
if frappe.db.get_value('Item', item_code, 'is_stock_item'):
bin_qty = get_bin_qty(item_code, warehouse)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
return bin_qty - pos_sales_qty
else:
if frappe.db.exists('Product Bundle', item_code):
return get_bundle_availability(item_code, warehouse)
def get_bundle_availability(bundle_item_code, warehouse):
product_bundle = frappe.get_doc('Product Bundle', bundle_item_code)
bundle_bin_qty = 1000000
for item in product_bundle.items:
item_bin_qty = get_bin_qty(item.item_code, warehouse)
item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse)
available_qty = item_bin_qty - item_pos_reserved_qty
max_available_bundles = available_qty / item.qty
if bundle_bin_qty > max_available_bundles:
bundle_bin_qty = max_available_bundles
pos_sales_qty = get_pos_reserved_qty(bundle_item_code, warehouse)
return bundle_bin_qty - pos_sales_qty
def get_bin_qty(item_code, warehouse):
bin_qty = frappe.db.sql("""select actual_qty from `tabBin`
where item_code = %s and warehouse = %s
limit 1""", (item_code, warehouse), as_dict=1)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
bin_qty = bin_qty[0].actual_qty or 0 if bin_qty else 0
return bin_qty - pos_sales_qty
return bin_qty[0].actual_qty or 0 if bin_qty else 0
def get_pos_reserved_qty(item_code, warehouse):
reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
@@ -522,4 +545,4 @@ def add_return_modes(doc, pos_profile):
mode_of_payment = pos_payment_method.mode_of_payment
if pos_payment_method.allow_in_returns and not [d for d in doc.get('payments') if d.mode_of_payment == mode_of_payment]:
payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company)
append_payment(payment_mode[0])
append_payment(payment_mode[0])

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

@@ -152,7 +152,7 @@ class PricingRule(Document):
frappe.throw(_("Valid from date must be less than valid upto date"))
def validate_condition(self):
if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition):
if self.condition and ("=" in self.condition) and re.match(r'[\w\.:_]+\s*={1}\s*[\w\.@\'"]+', self.condition):
frappe.throw(_("Invalid condition expression"))
#--------------------------------------------------------------------------------

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

@@ -19,7 +19,7 @@ frappe.ui.form.on('Process Statement Of Accounts', {
frappe.show_alert({message: __('Emails Queued'), indicator: 'blue'});
}
else{
frappe.msgprint('No Records for these settings.')
frappe.msgprint(__('No Records for these settings.'))
}
}
});
@@ -33,7 +33,7 @@ frappe.ui.form.on('Process Statement Of Accounts', {
type: 'GET',
success: function(result) {
if(jQuery.isEmptyObject(result)){
frappe.msgprint('No Records for these settings.');
frappe.msgprint(__('No Records for these settings.'));
}
else{
window.location = url;
@@ -92,7 +92,7 @@ frappe.ui.form.on('Process Statement Of Accounts', {
frm.refresh_field('customers');
}
else{
frappe.throw('No Customers found with selected options.');
frappe.throw(__('No Customers found with selected options.'));
}
}
}
@@ -129,4 +129,4 @@ frappe.ui.form.on('Process Statement Of Accounts Customer', {
}
})
}
});
});

View File

@@ -94,7 +94,7 @@ def get_report_pdf(doc, consolidated=True):
continue
html = frappe.render_template(template_path, \
{"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None,
{"filters": filters, "data": res, "ageing": ageing[0] if (doc.include_ageing and ageing) else None,
"letter_head": letter_head if doc.letter_head else None,
"terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms')
if doc.terms_and_conditions else None})
@@ -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

@@ -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
@@ -68,9 +68,6 @@ class PurchaseInvoice(BuyingController):
super(PurchaseInvoice, self).validate()
# apply tax withholding only if checked and applicable
self.set_tax_withholding()
if not self.is_return:
self.po_required()
self.pr_required()
@@ -251,11 +248,9 @@ class PurchaseInvoice(BuyingController):
if self.update_stock and (not item.from_warehouse):
if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]:
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]))
msg += _("because account {} is not linked to warehouse {} ").format(frappe.bold(item.expense_account), frappe.bold(item.warehouse))
msg += _("or it is not the default inventory account")
msg = _("Row {0}: Expense Head changed to {1} because account {2} is not linked to warehouse {3} or it is not the default inventory account").format(
item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]), frappe.bold(item.expense_account), frappe.bold(item.warehouse))
frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = warehouse_account[item.warehouse]["account"]
else:
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
@@ -266,8 +261,8 @@ class PurchaseInvoice(BuyingController):
if negative_expense_booked_in_pr:
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
msg += _("because expense is booked against this account in Purchase Receipt {}").format(frappe.bold(item.purchase_receipt))
msg = _("Row {0}: Expense Head changed to {1} because expense is booked against this account in Purchase Receipt {2}").format(
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt))
frappe.msgprint(msg, title=_("Expense Head Changed"))
item.expense_account = stock_not_billed_account
@@ -275,8 +270,9 @@ class PurchaseInvoice(BuyingController):
# If no purchase receipt present then book expense in 'Stock Received But Not Billed'
# This is done in cases when Purchase Invoice is created before Purchase Receipt
if for_validate and item.expense_account and item.expense_account != stock_not_billed_account:
msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account))
msg += _("as no Purchase Receipt is created against Item {}. ").format(frappe.bold(item.item_code))
msg = _("Row {0}: Expense Head changed to {1} as no Purchase Receipt is created against Item {2}.").format(
item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.item_code))
msg += "<br>"
msg += _("This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice")
frappe.msgprint(msg, title=_("Expense Head Changed"))
@@ -308,8 +304,8 @@ class PurchaseInvoice(BuyingController):
if not d.purchase_order:
msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code))
msg += "<br><br>"
msg += _("To submit the invoice without purchase order please set {} ").format(frappe.bold(_('Purchase Order Required')))
msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
msg += _("To submit the invoice without purchase order please set {0} as {1} in {2}").format(
frappe.bold(_('Purchase Order Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
throw(msg, title=_("Mandatory Purchase Order"))
def pr_required(self):
@@ -323,8 +319,8 @@ class PurchaseInvoice(BuyingController):
if not d.purchase_receipt and d.item_code in stock_items:
msg = _("Purchase Receipt Required for item {}").format(frappe.bold(d.item_code))
msg += "<br><br>"
msg += _("To submit the invoice without purchase receipt please set {} ").format(frappe.bold(_('Purchase Receipt Required')))
msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
msg += _("To submit the invoice without purchase receipt please set {0} as {1} in {2}").format(
frappe.bold(_('Purchase Receipt Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings'))
throw(msg, title=_("Mandatory Purchase Receipt"))
def validate_write_off_account(self):
@@ -404,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")
@@ -449,13 +446,17 @@ 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)
gl_entries = make_regional_gl_entries(gl_entries, self)
gl_entries = merge_similar_entries(gl_entries)
@@ -518,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)
@@ -608,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"))
@@ -822,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"
@@ -832,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"
@@ -982,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()
@@ -1000,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()
@@ -1090,6 +1099,7 @@ class PurchaseInvoice(BuyingController):
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
d.update(tax_withholding_details)
accounts.append(d.account_head)
if not accounts or tax_withholding_details.get("account_head") not in accounts:

View File

@@ -16,6 +16,7 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_tra
from erpnext.projects.doctype.project.test_project import make_project
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
from erpnext.stock.doctype.item.test_item import create_item
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"]
test_ignore = ["Serial No"]
@@ -229,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()
@@ -620,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)
@@ -631,13 +678,13 @@ 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):
pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
rejected_qty=1, rate=500, update_stock=1,
rejected_warehouse = "_Test Rejected Warehouse - _TC")
rejected_qty=1, rate=500, update_stock=1, rejected_warehouse = "_Test Rejected Warehouse - _TC",
allow_zero_valuation_rate=1)
self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].serial_no, "warehouse"),
pi.get("items")[0].warehouse)
@@ -950,12 +997,240 @@ 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
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_purchase_invoice
# create a new supplier to test
supplier = create_supplier(supplier_name = '_Test TDS Advance Supplier',
tax_withholding_category = 'TDS - 194 - Dividends - Individual')
# Update tax withholding category with current fiscal year and rate details
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, item='_Test Non Stock Item')
po.apply_tds = 1
po.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
po.save()
po.submit()
# Update Unrealized Profit / Loss Account which is used as default advance tax account
frappe.db.set_value('Company', '_Test Company', 'unrealized_profit_loss_account', '_Test Account Excise Duty - _TC')
# Create Payment Entry Against the order
payment_entry = get_payment_entry(dt='Purchase Order', dn=po.name)
payment_entry.paid_from = 'Cash - _TC'
payment_entry.save()
payment_entry.submit()
# Check GLE for Payment Entry
expected_gle = [
['_Test Account Excise Duty - _TC', 3000, 0],
['Cash - _TC', 0, 27000],
['Creditors - _TC', 27000, 0],
['TDS Payable - _TC', 0, 3000],
]
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry`
where voucher_type='Payment Entry' and voucher_no=%s
order by account asc""", (payment_entry.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)
# 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()
# Check GLE for Purchase Invoice
# Zero net effect on final TDS Payable on invoice
expected_gle = [
['_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, 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.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
fiscal_year = get_fiscal_year(date=date, company=company)
if not frappe.db.get_value('Tax Withholding Rate',
{'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}):
tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual')
tds_category.append('rates', {
'fiscal_year': fiscal_year[0],
'tax_withholding_rate': 10,
'single_threshold': 2500,
'cumulative_threshold': 0
})
tds_category.save()
if not frappe.db.get_value('Tax Withholding Account',
{'parent': 'TDS - 194 - Dividends - Individual', 'account': account}):
tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual')
tds_category.append('accounts', {
'company': company,
'account': account
})
tds_category.save()
def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
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)
@@ -978,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",
@@ -986,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",
@@ -994,7 +1273,8 @@ def make_purchase_invoice(**args):
"project": args.project,
"rejected_warehouse": args.rejected_warehouse or "",
"rejected_serial_no": args.rejected_serial_no or "",
"asset_location": args.location or ""
"asset_location": args.location or "",
"allow_zero_valuation_rate": args.get("allow_zero_valuation_rate") or 0
})
if args.get_taxes_and_charges:

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

@@ -12,6 +12,7 @@
"charge_type",
"row_id",
"included_in_print_rate",
"included_in_paid_amount",
"col_break1",
"account_head",
"description",
@@ -21,6 +22,7 @@
"cost_center",
"dimension_col_break",
"section_break_9",
"currency",
"tax_amount",
"tax_amount_after_discount_amount",
"total",
@@ -205,12 +207,28 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fetch_from": "account_head.account_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
},
{
"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",
"label": "Considered In Paid Amount"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2020-09-18 17:26:09.703215",
"modified": "2021-06-14 01:43:50.750455",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Taxes and Charges",

View File

@@ -17,7 +17,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
var me = this;
this._super();
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet'];
this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log', 'POS Closing Entry'];
if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
// show debit_to in print format
this.frm.set_df_property("debit_to", "print_hide", 0);
@@ -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 = {}
@@ -531,7 +533,7 @@ class SalesInvoice(SellingController):
# set pos values in items
for item in self.get("items"):
if item.get('item_code'):
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos)
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True)
for fname, val in iteritems(profile_details):
if (not for_validate) or (for_validate and not item.get(fname)):
item.set(fname, val)
@@ -840,16 +842,19 @@ 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)
self.make_loyalty_point_redemption_gle(gl_entries)
self.make_pos_gl_entries(gl_entries)
self.make_gle_for_change_amount(gl_entries)
self.make_write_off_gl_entry(gl_entries)
self.make_gle_for_rounding_adjustment(gl_entries)
@@ -883,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)
)
@@ -913,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:
@@ -938,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)
@@ -957,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(
@@ -983,7 +1002,13 @@ class SalesInvoice(SellingController):
def make_pos_gl_entries(self, gl_entries):
if cint(self.is_pos):
skip_change_gl_entries = not cint(frappe.db.get_single_value('Accounts Settings', 'post_change_gl_entries'))
for payment_mode in self.payments:
if skip_change_gl_entries and payment_mode.account == self.account_for_change_amount:
payment_mode.base_amount -= flt(self.change_amount)
if payment_mode.amount:
# POS, make payment entries
gl_entries.append(
@@ -1015,8 +1040,11 @@ class SalesInvoice(SellingController):
}, payment_mode_account_currency, item=self)
)
if not skip_change_gl_entries:
self.make_gle_for_change_amount(gl_entries)
def make_gle_for_change_amount(self, gl_entries):
if cint(self.is_pos) and self.change_amount:
if self.change_amount:
if self.account_for_change_amount:
gl_entries.append(
self.get_gl_dict({
@@ -1913,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

@@ -713,7 +713,7 @@ class TestSalesInvoice(unittest.TestCase):
si.submit()
self.assertEqual(si.paid_amount, 100.0)
self.pos_gl_entry(si, pos, 50)
self.validate_pos_gl_entry(si, pos, 50)
def test_pos_returns_with_repayment(self):
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_sales_return
@@ -749,7 +749,7 @@ class TestSalesInvoice(unittest.TestCase):
make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",
make_purchase_receipt(company= "_Test Company with perpetual inventory",
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
@@ -770,7 +770,45 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(pos.grand_total, 100.0)
self.assertEqual(pos.write_off_amount, -5)
def pos_gl_entry(self, si, pos, cash_amount):
def test_pos_with_no_gl_entry_for_change_amount(self):
frappe.db.set_value('Accounts Settings', None, 'post_change_gl_entries', 0)
make_pos_profile(company="_Test Company with perpetual inventory", income_account = "Sales - TCP1",
expense_account = "Cost of Goods Sold - TCP1", warehouse="Stores - TCP1", cost_center = "Main - TCP1", write_off_account="_Test Write Off - TCP1")
make_purchase_receipt(company= "_Test Company with perpetual inventory",
item_code= "_Test FG Item",warehouse= "Stores - TCP1", cost_center= "Main - TCP1")
pos = create_sales_invoice(company= "_Test Company with perpetual inventory",
debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1",
income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1",
cost_center = "Main - TCP1", do_not_save=True)
pos.is_pos = 1
pos.update_stock = 1
taxes = get_taxes_and_charges()
pos.taxes = []
for tax in taxes:
pos.append("taxes", tax)
pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 60})
pos.insert()
pos.submit()
self.assertEqual(pos.grand_total, 100.0)
self.assertEqual(pos.change_amount, 10)
self.validate_pos_gl_entry(pos, pos, 60, validate_without_change_gle=True)
frappe.db.set_value('Accounts Settings', None, 'post_change_gl_entries', 1)
def validate_pos_gl_entry(self, si, pos, cash_amount, validate_without_change_gle=False):
if validate_without_change_gle:
cash_amount -= pos.change_amount
# check stock ledger entries
sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
where voucher_type = 'Sales Invoice' and voucher_no = %s""",
@@ -1870,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
@@ -1899,69 +1939,129 @@ 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")
item.set('taxes', [])
item.append("taxes", {
"item_tax_template": "_Test Account Excise Duty @ 10 - _TC",
"minimum_net_rate": 0,
"maximum_net_rate": 500
})
item.append("taxes", {
"item_tax_template": "_Test Account Excise Duty @ 12 - _TC",
"minimum_net_rate": 501,
"maximum_net_rate": 1000
})
item.save()
sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True)
self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC")
# Apply discount
sales_invoice.apply_discount_on = 'Net Total'
sales_invoice.discount_amount = 300
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'):
@@ -2012,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({
@@ -2038,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()
@@ -2050,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'
@@ -2057,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
@@ -2065,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
@@ -2085,27 +2210,6 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
doc.assertEqual(expected_gle[i][2], gle.credit)
doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
def test_item_tax_validity(self):
item = frappe.get_doc("Item", "_Test Item 2")
if item.taxes:
item.taxes = []
item.save()
item.append("taxes", {
"item_tax_template": "_Test Item Tax Template 1 - _TC",
"valid_from": add_days(nowdate(), 1)
})
item.save()
sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC"
self.assertRaises(frappe.ValidationError, sales_invoice.save)
item.taxes = []
item.save()
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
@@ -2123,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",
@@ -2134,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

@@ -1,8 +1,10 @@
{
"actions": [],
"creation": "2013-04-24 11:39:32",
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"charge_type",
"row_id",
@@ -10,12 +12,14 @@
"col_break_1",
"description",
"included_in_print_rate",
"included_in_paid_amount",
"accounting_dimensions_section",
"cost_center",
"dimension_col_break",
"section_break_8",
"rate",
"section_break_9",
"currency",
"tax_amount",
"total",
"tax_amount_after_discount_amount",
@@ -24,7 +28,7 @@
"base_total",
"base_tax_amount_after_discount_amount",
"item_wise_tax_detail",
"parenttype"
"dont_recompute_tax"
],
"fields": [
{
@@ -173,17 +177,6 @@
"oldfieldtype": "Small Text",
"read_only": 1
},
{
"fieldname": "parenttype",
"fieldtype": "Data",
"hidden": 1,
"in_filter": 1,
"label": "Parenttype",
"oldfieldname": "parenttype",
"oldfieldtype": "Data",
"print_hide": 1,
"search_index": 1
},
{
"fieldname": "accounting_dimensions_section",
"fieldtype": "Section Break",
@@ -192,15 +185,43 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"fetch_from": "account_head.account_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Account Currency",
"options": "Currency",
"read_only": 1
},
{
"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,
"modified": "2019-05-25 22:59:38.740883",
"links": [],
"modified": "2021-07-27 12:40:59.051803",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "ASC"
}

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
}

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