Compare commits

..

386 Commits

Author SHA1 Message Date
Rohit Waghchaure
ab904c22cc Merge branch 'version-13-pre-release' into version-13 2021-11-09 20:16:01 +05:30
Rohit Waghchaure
6b77bac7da bumped to version 13.14.0 2021-11-09 20:36:00 +05:50
rohitwaghchaure
b9da89a90b Merge pull request #28305 from rohitwaghchaure/change-log-for-v13-14-0
chore: Added change log for version 13.14.0
2021-11-09 20:13:44 +05:30
Rohit Waghchaure
f3cfb93a5f chore: Added change log for version 13.14.0 2021-11-09 20:09:09 +05:30
mergify[bot]
fa2f1348ec fix(India setup): setup company independent fixtures for patch (#28304)
(cherry picked from commit 88b5bda34b)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-11-09 19:50:14 +05:30
rohitwaghchaure
346c76cf38 Merge pull request #28290 from frappe/mergify/bp/version-13-pre-release/pr-28150
feat: provision to close the Work Order (backport #28150)
2021-11-09 16:38:10 +05:30
rohitwaghchaure
81e7ebc112 Merge pull request #28293 from frappe/mergify/bp/version-13-pre-release/pr-28219
feat: provision to have limited parameters for in-process quality inspection (backport #28219)
2021-11-09 16:37:37 +05:30
Diksha Jadhav
bb9713a7b2 refactor: use fetch from property for qi template on job card
(cherry picked from commit 467324c87f)
2021-11-09 10:23:00 +00:00
Diksha Jadhav
ac54e80856 feat: provision to have limited parameters for in-process quality inspection
(cherry picked from commit 6c45f8b2c4)
2021-11-09 10:22:59 +00:00
Diksha Jadhav
3c78ac21d9 feat(manufacturing): add link field for quality inspection template on operation
(cherry picked from commit 281a9cc749)
2021-11-09 10:22:58 +00:00
Anupam
515b8dd8ca fix: get_planned_qty chnages
(cherry picked from commit 663a7afe4d)
2021-11-09 10:16:26 +00:00
Anupam
dac0d87e16 fix: test cases
(cherry picked from commit 27709a1c71)
2021-11-09 10:16:25 +00:00
Anupam
365572f5ea fix: testcases:
(cherry picked from commit 7044ae5e39)
2021-11-09 10:16:25 +00:00
Anupam
029e66709d fix: linter isuue
(cherry picked from commit cc15cf6ae2)
2021-11-09 10:16:24 +00:00
Anupam
8851b7adcf fix: sider isuue
(cherry picked from commit ba47bd02b6)
2021-11-09 10:16:24 +00:00
Anupam
116210dcea fix: validate job card
(cherry picked from commit 9b4c7e4796)
2021-11-09 10:16:23 +00:00
Anupam
dce943b41f fix: test cases
(cherry picked from commit 9c0906f1b5)
2021-11-09 10:16:23 +00:00
Anupam
cb209d9b57 fix: linter issues
(cherry picked from commit e36da4d137)
2021-11-09 10:16:23 +00:00
Anupam
7c7493c91d fix: linter issues
(cherry picked from commit 59e4fd980c)
2021-11-09 10:16:22 +00:00
Anupam
f3da88e301 fix: added testcase
(cherry picked from commit 530a0f481e)
2021-11-09 10:16:22 +00:00
Anupam
8ddeb83191 fix: sider issue
(cherry picked from commit 264b0df9ff)
2021-11-09 10:16:21 +00:00
Anupam
47f8f3d9dd fix: sider issue
(cherry picked from commit 55e97dce8a)
2021-11-09 10:16:20 +00:00
Anupam
44c53deb90 fix: sider issue
(cherry picked from commit e290fe0721)
2021-11-09 10:16:20 +00:00
Anupam
d43aecbe13 feat: added confirm dialog on closing of workorder
(cherry picked from commit 5d4c5652af)
2021-11-09 10:16:19 +00:00
Anupam
e8ef54f4d7 feat: provision to close the Work Order
(cherry picked from commit 23af036894)
2021-11-09 10:16:18 +00:00
mergify[bot]
eacf26d618 fix: show full item name in search widget (#28283) (#28285)
(cherry picked from commit 34f5283c17)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-09 12:14:54 +05:30
mergify[bot]
40b5bb1d15 fix: do not generate multiple invoices (#28216) 2021-11-08 20:07:57 +05:30
Deepesh Garg
5d46f765a6 Merge pull request #28276 from frappe/mergify/bp/version-13-pre-release/pr-28262
fix: Taxjar customer_address fix, currency fix (backport #28262)
2021-11-08 19:04:06 +05:30
Deepesh Garg
2654098ce2 Merge pull request #28274 from frappe/mergify/bp/version-13-pre-release/pr-28272
fix: KSA VAT setup issues (backport #28272)
2021-11-08 18:52:20 +05:30
Subin Tom
a403200516 fix: company condition fix, added company field
(cherry picked from commit 7ad2717acc)
2021-11-08 13:12:00 +00:00
Subin Tom
1dc7cb8ad1 fix: fixed company field, updated patch
(cherry picked from commit 7f2d304f32)
2021-11-08 13:12:00 +00:00
Subin Tom
abe6ef4cd4 fix: Added company field, filtered account heads
(cherry picked from commit 902c03cd37)
2021-11-08 13:12:00 +00:00
Subin Tom
3d1b833f35 fix: Fixed customer address variable, sales invoice item field currency issue
(cherry picked from commit 904010ab64)
2021-11-08 13:11:59 +00:00
Deepesh Garg
2dc12505b2 fix: Resolve conflicts 2021-11-08 18:16:46 +05:30
Deepesh Garg
f5251b5a86 fix: Add patch to make custom fields
(cherry picked from commit 508832e90a)

# Conflicts:
#	erpnext/patches.txt
2021-11-08 12:39:55 +00:00
Deepesh Garg
aa6caa00bf fix: KSA VAT setup issues
(cherry picked from commit c81d4734c4)
2021-11-08 12:39:54 +00:00
Deepesh Garg
35bd31e939 Merge pull request #28270 from frappe/mergify/bp/version-13-pre-release/pr-28166
feat(Print Format): KSA VAT Invoice (backport #28166)
2021-11-08 17:15:49 +05:30
ahmadpak
0ba59049f9 update(Print Format): Sales Invoice
- KSA VAT Invoice
Customer Identification Number Added

(cherry picked from commit 8df50cf1e0)
2021-11-08 09:58:11 +00:00
ahmadpak
9f6b0dbfdf new (Print Format): KSA VAT Invoice
(cherry picked from commit 2a5beec885)
2021-11-08 09:58:11 +00:00
mergify[bot]
79be341ea4 feat: replace newline in remarks (DATEV report) (#28152) (#28248)
(cherry picked from commit 114028e473)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2021-11-05 11:15:18 +05:30
Suraj Shetty
b3dc199118 Merge pull request #28191 from frappe/build-on-release
ci: migrate docker to github actions
2021-11-03 18:10:20 +05:30
Saqib
9a3c6694b9 Merge pull request #28221 from frappe/mergify/bp/version-13-pre-release/pr-27946
fix(Payment Entry): splitting outstanding rows as per payment terms (backport #27946)
2021-11-03 15:41:29 +05:30
Anuja Pawar
2c9266807a fix(Payment Entry): splitting outstanding rows as per payment terms (#27946)
(cherry picked from commit d72709dd81)
2021-11-03 09:18:40 +00:00
Revant Nandgaonkar
afb236a06b ci: change GITHUB_PAT to CI_PAT 2021-11-03 13:56:50 +05:30
mergify[bot]
94905df774 fix: ignore unsupported methods while resyncing (#28210) (#28214)
(cherry picked from commit 72a050fb0b)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-03 09:47:00 +05:30
Marica
fa5cee479f Merge pull request #28204 from frappe/mergify/bp/version-13-pre-release/pr-28202
fix: Serial Nos not set in the row after scanning in popup (backport #28202)
2021-11-02 20:41:33 +05:30
Deepesh Garg
885f1e0fd8 Merge pull request #28207 from frappe/mergify/bp/version-13-pre-release/pr-28205
fix: Error on LDC creation (backport #28205)
2021-11-02 20:29:43 +05:30
Deepesh Garg
e358d34c4f fix: Error on LDC creation
(cherry picked from commit 66348e1a03)
2021-11-02 14:59:10 +00:00
marination
093d9f4a70 fix: Serial Nos not set in the row after scanning in popup
- Avoid whitspaces while calculating length of serial nos

(cherry picked from commit 734b57deec)
2021-11-02 14:48:40 +00:00
mergify[bot]
50fbc167f3 fix(Payment Reconciliation): clear child tables on company/party change (#28194) 2021-11-02 17:12:11 +05:30
Marica
0731454f50 Merge pull request #28196 from frappe/mergify/bp/version-13-pre-release/pr-28195
fix: (ux) Remove warehouse filter on Batch field for Material Receipt (backport #28195)
2021-11-02 16:28:02 +05:30
marination
b81dfdcd26 chore: Add comment above fix for future reference
(cherry picked from commit 48886ee705)
2021-11-02 10:40:02 +00:00
marination
68809159ba fix: Remove warehouse filter on Batch field for Material Receipt
(cherry picked from commit 048210a8f6)
2021-11-02 10:40:00 +00:00
Revant Nandgaonkar
1736029733 chore: migrate docker to github actions 2021-11-02 12:03:22 +05:30
Deepesh Garg
982960fc0a Merge pull request #28177 from frappe/mergify/bp/version-13-pre-release/pr-26735
fix: COGS account in purchase receipt (backport #26735)
2021-11-01 16:51:11 +05:30
Deepesh Garg
bb7d661a04 fix: Resolve conflicts 2021-11-01 16:23:39 +05:30
Ankush Menat
c6557a136c fix: use warehouse to find company
(cherry picked from commit f7ffe04a4b)
2021-11-01 15:31:11 +05:30
Ankush Menat
271dad941b fix: pass company while fetching valuation rate
If company is not supplied and valuation rate is 0, then default
company is used for checking if perpetual inventory is enabled or not.
This makes little sense as different companies can have different
setting for perpetual inventory.

(cherry picked from commit a0727b2e82)
2021-11-01 15:31:11 +05:30
Rohit Waghchaure
e9d1cbb339 fix: COGS account in purchase receipt
(cherry picked from commit 2a14f255cf)

# Conflicts:
#	erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
2021-11-01 07:26:09 +00:00
mergify[bot]
18dddfdea9 fix: remove duplicate field from selling_settings (#28174)
fix https://github.com/frappe/erpnext/issues/28155

(cherry picked from commit 1cc4eddacb)

Co-authored-by: ahmadRagheb <ahmedragheb75@gmail.com>
2021-11-01 11:11:40 +05:30
Deepesh Garg
978d1cde2d Merge pull request #28165 from frappe/mergify/bp/version-13-pre-release/pr-28162
fix: Error for missing PAN no field (backport #28162)
2021-10-31 18:50:10 +05:30
rohitwaghchaure
feaae330d5 Merge pull request #28170 from frappe/mergify/bp/version-13-pre-release/pr-28168
fix: patch update_category_in_ltds_certificate (backport #28168)
2021-10-31 10:28:09 +05:30
Rohit Waghchaure
060127663a fix: patch update_category_in_ltds_certificate
(cherry picked from commit cae29b71d8)
2021-10-31 04:27:51 +00:00
rohitwaghchaure
88bf748275 Merge pull request #28159 from rohitwaghchaure/merge-hotfix-to-pre-release-for-13-14
chore: merge branch 'version-13-hotfix' into 'version-13-pre-release'
2021-10-30 22:33:26 +05:30
Deepesh Garg
aa464cc615 fix: Error for missing PAN no field
(cherry picked from commit 541c892f97)
2021-10-30 14:00:07 +00:00
Rohit Waghchaure
8581b5cdea chore: merge branch 'version-13-hotfix' into 'version-13-pre-release' 2021-10-30 15:15:19 +05:30
mergify[bot]
9abb467127 fix: Make status filter optional (#28151) 2021-10-29 18:16:23 +05:30
mergify[bot]
f16e0e17cc fix: POS consolidated invoice rounded total issue (#28146) 2021-10-29 18:05:49 +05:30
Deepesh Garg
fe59c313d6 Merge pull request #28148 from frappe/mergify/bp/version-13-hotfix/pr-28145
fix: COA importer importing all accounts as group (backport #28145)
2021-10-29 18:03:58 +05:30
Ankush Menat
9e9f730dd1 fix: sort by creation to break tie
(cherry picked from commit ff9cfe0d14)
2021-10-29 17:42:05 +05:30
Ankush Menat
264ffe05b4 refactor: simplify sr no fetching
(cherry picked from commit f4b60a48f5)
2021-10-29 17:42:05 +05:30
Ankush Menat
42686f92e9 fix: fetch serial nos from ledger unconditionally
(cherry picked from commit 2aa019ae4c)
2021-10-29 17:42:05 +05:30
Noah Jacob
7931cfd77b refactor: replaced db.sql with qb
(cherry picked from commit deb6b38fab)
2021-10-29 17:42:05 +05:30
Noah Jacob
835d96c727 fix: incorrect amount of serial_nos fetched
(cherry picked from commit b44945380d)
2021-10-29 17:42:05 +05:30
Deepesh Garg
f7cf3fed8e Merge pull request #28144 from frappe/mergify/bp/version-13-hotfix/pr-27994
fix: incorrect VAT Amount in UAE VAT 201 report (backport #27994)
2021-10-29 17:20:13 +05:30
Deepesh Garg
0664e64003 fix: COA importer importing all accounts as group
(cherry picked from commit 8ccd3fee9e)
2021-10-29 11:37:11 +00:00
Deepesh Garg
4f7046e6c2 Merge pull request #28143 from frappe/mergify/bp/version-13-hotfix/pr-28135
fix: Accounting Dimension filters not honouring user permissions (backport #28135)
2021-10-29 17:04:45 +05:30
Dany Robert
43ca66f461 fix: wrong vat amount
(cherry picked from commit 4c499e804a)
2021-10-29 09:13:18 +00:00
Dany Robert
ff7423f15f fix: incorrect VAT Amount in UAT VAT 201 report
(cherry picked from commit 1aa34d1780)
2021-10-29 09:13:17 +00:00
Deepesh Garg
7cbf577f1f fix: Accounting Dimension filters not honouring user permissions
(cherry picked from commit aa9e78bed1)
2021-10-29 09:10:50 +00:00
mergify[bot]
1454f8bc96 fix: Skip empty rows while updating unsaved BOM cost (#28136) (#28142)
- Dont try to get valuation rate if row has no item code
- Dont try to add exploded items if row has no item code

(cherry picked from commit 292419bc9e)

Co-authored-by: Marica <maricadsouza221197@gmail.com>
2021-10-29 14:19:51 +05:30
mergify[bot]
a33ebbdc54 test: remove unnecessary creation of new company (#28137) (#28140)
(cherry picked from commit afe09d4e80)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-29 14:19:25 +05:30
Deepesh Garg
ee6da35c0b Merge pull request #28134 from frappe/mergify/bp/version-13-hotfix/pr-28122
fix: Consolidated Financial Report throws error for empty equity data list (backport #28122)
2021-10-29 13:51:48 +05:30
Deepesh Garg
1c0ae92912 Merge pull request #28133 from frappe/mergify/bp/version-13-hotfix/pr-27609
fix: Unlink PO on cancelling SO (backport #27609)
2021-10-29 13:51:21 +05:30
Subin Tom
3fc2442622 fix: Consolidated Financial Report throws error for empty equity data list
(cherry picked from commit d786855d94)
2021-10-29 06:42:13 +00:00
Deepesh Garg
a60ecb95b0 fix: Ignore PO on So cancel
(cherry picked from commit 051aaa708d)
2021-10-29 06:28:28 +00:00
GangaManoj
ed58f206fa fix: Remove unused imports
(cherry picked from commit d24cfff388)
2021-10-29 06:28:27 +00:00
GangaManoj
305b9508e6 fix: Remove debugger
(cherry picked from commit 1a9d2684e2)
2021-10-29 06:28:27 +00:00
GangaManoj
d47007adb2 fix: Remove print statements
(cherry picked from commit 8844fdbf23)
2021-10-29 06:28:26 +00:00
GangaManoj
7c42b8b702 fix: Unlink PO on cancelling SO
(cherry picked from commit e77534fe13)
2021-10-29 06:28:25 +00:00
GangaManoj
2fb18afea0 fix: Unlink PO on cancelling SO
(cherry picked from commit 8396f24e70)
2021-10-29 06:28:24 +00:00
Deepesh Garg
c822f286c7 Merge pull request #28125 from deepeshgarg007/ksa-vat-v13
feat(regional): KSA E-Invoicing and VAT Report
2021-10-29 11:15:19 +05:30
Deepesh Garg
6260f0caa1 Merge pull request #28128 from frappe/mergify/bp/version-13-hotfix/pr-28071
fix : Get LTDS based on tax withholding category (backport #28071)
2021-10-29 09:05:12 +05:30
Deepesh Garg
4019148a42 fix: Resolve conflicts 2021-10-28 20:26:38 +05:30
Deepesh Garg
7a25d5f2de fix: Rewrite patch using query builder
(cherry picked from commit 09a5616e2d)
2021-10-28 14:31:06 +00:00
Deepesh Garg
1ba0111e16 fix: Replace section code with tax withholding category in LDC
(cherry picked from commit bf13d183d8)

# Conflicts:
#	erpnext/patches.txt
2021-10-28 14:31:06 +00:00
Deepesh Garg
e9c3d3ff0d fix: Get LTDS based on tax withholding category
(cherry picked from commit e6e804e7d7)
2021-10-28 14:31:05 +00:00
Ahmad
6d39b90b8e refactor: make strings translate 2021-10-28 17:53:41 +05:30
Ahmad
b69381117f fix: pre-commit hooks 2021-10-28 17:53:22 +05:30
Ahmad
301b94e06a fix: pre-commit hooks 2021-10-28 17:53:22 +05:30
Ahmad
30f3b4804d refactor (regional): KSA utils 2021-10-28 17:53:22 +05:30
Ahmad
0313b44f1f Update erpnext/regional/saudi_arabia/utils.py
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-28 17:53:22 +05:30
Ahmad
f9770b69b2 Update erpnext/regional/saudi_arabia/utils.py
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-28 17:53:22 +05:30
Ahmad
5f7c5bcac8 fix: indentations 2021-10-28 17:52:53 +05:30
Ahmad
873ed1ae4f refactor(regional): moved methos to region specific utils for KSA 2021-10-28 17:52:02 +05:30
Ahmad
3fca08e3e8 Update erpnext/regional/saudi_arabia/setup.py
Method name updated

Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-28 17:46:30 +05:30
Ahmad
220ab16698 Refactor erpnext/regional/__init__.py
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-28 17:44:26 +05:30
Ahmad
a8ba52e8a5 Update erpnext/regional/report/ksa_vat/ksa_vat.py
String made translatable

Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-28 17:44:19 +05:30
Ahmad
60fd96085c feat(regional): QR Code generation for Saudi Arabia Sales Invoices 2021-10-28 17:44:04 +05:30
Ahmad
e03965afa5 feat(Regional): KSA VAT Report 2021-10-28 17:39:15 +05:30
Deepesh Garg
d116aa6f23 Merge pull request #28116 from frappe/mergify/bp/version-13-hotfix/pr-28114
fix: Autoemail report not showing dynamic report filters (backport #28114)
2021-10-28 11:57:28 +05:30
mergify[bot]
9c7cdc1079 fix: opportunity link is missign from customer (#28110) (#28121)
(cherry picked from commit 4787a75208)

Co-authored-by: Anupam Kumar <anupamvns0099@gmail.com>
2021-10-28 11:48:19 +05:30
Marica
a19f0f484c Merge pull request #28098 from marination/so-quote-portal
fix: SO/Quotation Portal Missing Images
2021-10-28 00:16:07 +05:30
Marica
5388ecf85e Merge pull request #27926 from frappe/mergify/bp/version-13-hotfix/pr-27914
fix: Avoid automatic customer creation on website user login (backport #27914)
2021-10-28 00:05:55 +05:30
Deepesh Garg
b34e737930 fix: Autoemail report not showing dynamic report filters
(cherry picked from commit 3a6894fb9c)
2021-10-27 14:29:38 +00:00
Ankush Menat
56c98aa59e fix(ux): make qty 1 by default in WO
(cherry picked from commit d81b87d9b3)
2021-10-27 19:49:00 +05:30
Ankush Menat
aa210ba6c8 fix: don't show blocked supplier in autocomplete
(cherry picked from commit 2221c9ed89)
2021-10-27 19:49:00 +05:30
Ankush Menat
4bfacabf85 fix(ux): alternative item two way validation
(cherry picked from commit 5902762ec8)
2021-10-27 19:49:00 +05:30
Ankush Menat
99a1eea982 fix: remove bad hardcoded max value
(cherry picked from commit 5f9bd9b8e9)
2021-10-27 19:49:00 +05:30
mergify[bot]
48acb56cb0 fix: Remove pointless buttons from Payment Order (#28108)
fix: Remove pointless buttons from Payment Order
(cherry picked from commit c9f3ea5fea)

Co-authored-by: Ganga Manoj <ganga.manoj98@gmail.com>
2021-10-27 16:16:31 +05:30
mergify[bot]
5867d97e7c fix(ux): misleading label for image fields (#28107) (#28109)
(cherry picked from commit e0cf45e7ec)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-27 15:29:08 +05:30
mergify[bot]
e757970db3 fix(general_ledger): Order by in case Group by Account (#28093) (#28106)
* Update general_ledger.py

Fix order_by_statement if filter group by: Group by Account

* chore: whitespace

Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
(cherry picked from commit f24ed6723e)

Co-authored-by: hendrik <hendrik.zeta@gmail.com>
2021-10-27 14:45:05 +05:30
Saqib
2a60a65ccd Merge pull request #28102 from frappe/mergify/bp/version-13-hotfix/pr-27916
perf(minor): improve sales invoice submission (backport #27916)
2021-10-27 14:26:38 +05:30
Afshan
db5593287e Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27916 2021-10-27 14:05:51 +05:30
mergify[bot]
e8b46bf3a3 fix(ux): add naming series to ERPNext setting workspace (backport #28090) (#28103)
* fix(ux): add naming series to ERPNext setting workspace  (#28090)

* fix(ux): add naming series to setting workspace

* fix: doctype link to naming series

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

Co-authored-by: Summayya <frappe@Summayyas-MacBook-Air.local>
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
(cherry picked from commit 0806e32049)

# Conflicts:
#	erpnext/setup/workspace/erpnext_settings/erpnext_settings.json

* fix: conflicts

Co-authored-by: Summayya Hashmani <58825865+sumaiya2908@users.noreply.github.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-27 14:03:24 +05:30
Marica
67e5e95466 Merge pull request #27931 from marination/optimize-get-attribute-filters-hotfix
perf: Optimize get_attribute_filters (#26729)
2021-10-27 13:31:58 +05:30
mergify[bot]
f1b7bb8878 fix: Update receivable/payable account on company change (backport #28057) (#28087)
* fix: Update receivable/payable account on company change

(cherry picked from commit 65025fb628)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.js

* fix: Update sales_invoice.js

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-27 13:30:32 +05:30
mergify[bot]
fb742476f8 fix: Payment Terms validation precision (#28104)
(cherry picked from commit 9c1705205f)

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-27 13:26:57 +05:30
mergify[bot]
d4b4bd9d97 fix: update production plan status (backport #27567)
* fix: update production plan status #27567

fix: update production plan status
(cherry picked from commit 05831b18ad)

# Conflicts:
#	erpnext/patches.txt

* fix: resolve conflicts

Co-authored-by: Alan <2.alan.tom@gmail.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-27 13:20:51 +05:30
Afshan
accb98ccf4 Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27916 2021-10-27 12:58:30 +05:30
Deepesh Garg
6acab32934 Merge pull request #28085 from frappe/mergify/bp/version-13-hotfix/pr-28055
fix(UX): Add mandatory depends on condition for reference no and date fields (backport #28055)
2021-10-27 11:57:20 +05:30
Saqib
5d4d6bb52b fix: sider
(cherry picked from commit ac381d21fe)
2021-10-27 06:13:33 +00:00
Ankush Menat
a2a462f2f5 fix: undo changes to allow negative stock flag
(cherry picked from commit 7bafa11d57)
2021-10-27 06:13:32 +00:00
Saqib Ansari
b1efb7f80b perf: skip insertion of stock ledger entry
(cherry picked from commit c7fc609236)
2021-10-27 06:13:32 +00:00
Saqib Ansari
97fc449222 perf: get total company stock only for purchase order
(cherry picked from commit eb3aae870f)
2021-10-27 06:13:32 +00:00
Saqib Ansari
cb0168ae65 perf: fetch mode of payments data in single query
(cherry picked from commit 7b691beabb)
2021-10-27 06:13:31 +00:00
Saqib Ansari
de38c70707 perf: skip get_pricing_rules if no pricing rule exists
(cherry picked from commit a500252570)
2021-10-27 06:13:31 +00:00
Saqib
cb97e950e6 feat(e-invoicing): dispatch address (#28084) 2021-10-27 11:39:00 +05:30
Ankush Menat
a046da1e61 test: picklist item grouping
(cherry picked from commit 479ecb8de0)
2021-10-27 11:30:30 +05:30
Ankush Menat
28026f7f1c refactor: use defaultdict and enumeration
(cherry picked from commit 6942900555)
2021-10-27 11:30:30 +05:30
Diksha Jadhav
93a0ea7118 feat(pick list): group items based on item code and warehouse before printing picklist
(cherry picked from commit f2d136e574)
2021-10-27 11:30:30 +05:30
mergify[bot]
a30cfbce42 fix: change modified timestamp to apply changes on migrate #28095 (#28099)
fix: change modified timestamp to apply changes on migrate
(cherry picked from commit 2920f2f614)

Co-authored-by: Dany Robert <rtdany10@gmail.com>
2021-10-27 11:20:13 +05:30
mergify[bot]
019c5a338d fix(ux): overbiling message in SO->SI, PO->PI (bp #28088)
(cherry picked from commit 6ec047cba9)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-27 11:08:23 +05:30
gsi-maruiz
8cad23b8fb fix: add filter to query to avoid send reminder for zero years (#28092)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-27 11:00:56 +05:30
marination
dd2dba6f01 style: Fixed indentation for visible heirarchy 2021-10-27 10:57:48 +05:30
Deepesh Garg
f63a71e2cc fix(minor): Add mandatory depends on condition for reference no and date fields
(cherry picked from commit a20058a343)
2021-10-26 14:33:10 +00:00
mergify[bot]
f81c5cd478 fix: POS Closing Entry without linked invoices (#28077) 2021-10-26 14:42:44 +05:30
mergify[bot]
a23ef95cd8 refactor: shows opening balance from filtered from_date (#26877) (#28072)
* refactor: shows opening balance from filtered from_date

* refactor: opening balance considered from filtered from_date in stock ledger

* fix: check if stock reco is opening and misc cleanups

(cherry picked from commit fdaf93f76c)

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-10-25 09:09:44 +05:30
Deepesh Garg
943def5faa Merge pull request #28014 from deepeshgarg007/tds_computation_summary_fixes
fix: Error in TDS computation summary
2021-10-23 13:16:30 +05:30
Ankush Menat
7a08f8aeec chore: change semgrep rules repo name
[skip ci]
2021-10-22 22:40:56 +05:30
mergify[bot]
a082d70553 ci: move semgrep rules out of repo (backport #28067)
* ci: move semgrep rules out of repo (#28067)

Moving semgrep rules out of repos as it's unnecessary to maintain
same ruleset for different repos and different branches.

(cherry picked from commit cc1baae5eb)

# Conflicts:
#	.github/helper/semgrep_rules/frappe_correctness.py
#	.github/helper/semgrep_rules/frappe_correctness.yml
#	.github/helper/semgrep_rules/report.py
#	.github/helper/semgrep_rules/ux.py
#	.github/workflows/linters.yml

* fix: resolve conflicts

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-22 21:58:45 +05:30
mergify[bot]
60620fe335 fix: don't reset rates in Timesheet Detail when Activity Type is cleared (#28056)
* fix: don't reset rates when activity type is cleared

* refactor: suggestions from review

Co-authored-by: Sagar Vora <sagar@resilient.tech>

* refactor: suggestions from review (fix)

* style: fix sider

* fix: sider issue

Co-authored-by: Sagar Vora <sagar@resilient.tech>
(cherry picked from commit 2bdaf7bb23)

Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com>
2021-10-22 14:06:11 +05:30
marination
d7e55387fc fix: SO Portal fixes
- SO Portal: fixed missing images issue
- SO Portal: fallback state when no images
- SO Portal: code indentation in `order_macros.html`
- SO Portal: Actions and indicator font size
- Recommendations: fixed space between image and title
- Recommendations: give empty image state min height
2021-10-21 20:14:28 +05:30
mergify[bot]
46567f0fe9 refactor: move process loss report to manufacturing (#28043) (#28047)
* refactor: move process loss report to manufacturing

* test: fix process loss report test

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
(cherry picked from commit 2849297471)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-10-21 11:11:53 +05:30
Ankush Menat
5ed32b5995 fix: unused imports 2021-10-21 11:04:40 +05:30
Devin Slauenwhite
152f9b0a43 fix: useless validation message (#28029)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-21 10:58:35 +05:30
Ankush Menat
71e517f043 test: fix get_attribute_filter test
The function returns strings directly instead of objects now.
2021-10-21 10:55:11 +05:30
mergify[bot]
e0f2130731 feat: employee initial work history updated when transfer is performed (#27768) (#28045)
* feat: employee initial work history updated when transfer is performed

* fix: sider

* fix: remove commit statement

* fix: tests and code formatting

* fix: tests

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
(cherry picked from commit 03bfc77940)

Co-authored-by: Mohammed Yusuf Shaikh <49878143+mohammedyusufshaikh@users.noreply.github.com>
2021-10-21 10:34:31 +05:30
Rohit Waghchaure
b8d75ff241 Merge branch 'version-13-pre-release' into version-13 2021-10-20 21:30:20 +05:30
Rohit Waghchaure
a3b7682935 bumped to version 13.13.0 2021-10-20 21:50:20 +05:50
rohitwaghchaure
200f6da8b2 Merge pull request #28040 from rohitwaghchaure/change-log-for-v13-13
chore: change log for v13.13.0
2021-10-20 21:23:39 +05:30
Rohit Waghchaure
7c9018f401 chore: change log for v13.13.0 2021-10-20 21:15:13 +05:30
mergify[bot]
4f5d67883c fix: consolidated report issue #28035 (#28039)
fix: consolidated report issue
(cherry picked from commit 871cb1157f)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
2021-10-20 21:10:45 +05:30
Ankush Menat
5ba315eb96 test: execute manufacturing reports
(cherry picked from commit da3635b94f)
2021-10-20 21:00:11 +05:30
Ankush Menat
408c4a6f54 fix: remove debug from query
(cherry picked from commit 126ba16740)
2021-10-20 21:00:11 +05:30
Ankush Menat
e357541509 fix: remove employee_name from job card summary
This field doesn't exist and it's moved on individual line level logs.

(cherry picked from commit 8221e7e01f)
2021-10-20 21:00:11 +05:30
mergify[bot]
1fae8f1fcb Merge pull request #28038 from frappe/mergify/bp/version-13-hotfix/pr-28036
fix: incorrect field name (backport #28036)
2021-10-20 20:55:00 +05:30
Ankush Menat
8fffd1597d fix: dont recompute item wise taxes from front end
(cherry picked from commit 393749a611)
2021-10-20 19:44:26 +05:30
mergify[bot]
34e92ab229 fix: incorrect status being set in Invoices (backport #28019) (#28031)
* fix: incorrect status being set in Invoices (#28019)

Co-authored-by: Pruthvi Patel <pruthvipatel145@gmail.com>
(cherry picked from commit 8d9d0987fe)

# Conflicts:
#	erpnext/patches.txt

* fix: merge conflict

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-10-20 19:31:47 +05:30
Sagar Vora
ffadd671b7 fix: add mistakenly removed patches 2021-10-20 19:26:15 +05:30
mergify[bot]
47befa697d fix: incorrect status being set in Invoices (backport #28019) (#28030)
* fix: incorrect status being set in Invoices (#28019)

Co-authored-by: Pruthvi Patel <pruthvipatel145@gmail.com>
(cherry picked from commit 8d9d0987fe)

* fix: merge conflict

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-10-20 19:24:19 +05:30
mergify[bot]
9ce7ea692d fix: avoid resetting employee on amending timesheets (#28025) (#28026)
(cherry picked from commit 261f80c5ca)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-20 17:45:43 +05:30
mergify[bot]
a739bf90c4 feat: Tax for recurring additional salary (backport #27459) (#28024)
* feat: Tax for recurring additional salary (#27459)

* fix: Logic for tax calculation on recurring additional salary

* fix: Get actual amount always in case of overwritten additional salary even if based on payment days

* feat: Test case added for recurring additional salary

* fix: use query builder to get additional salaries instead of raw SQL

* fix: query formatting and remove trailing spaces

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
(cherry picked from commit 2ef4844a3c)

# Conflicts:
#	erpnext/payroll/doctype/salary_slip/salary_slip.py
#	erpnext/payroll/doctype/salary_slip/test_salary_slip.py

* fix: conflicts

Co-authored-by: Nabin Hait <nabinhait@gmail.com>
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-20 16:20:25 +05:30
Jannat Patel
676c5280cc Merge pull request #28016 from frappe/mergify/bp/version-13-pre-release/pr-27728 2021-10-20 15:53:48 +05:30
Marica
e0decb0ae2 Merge pull request #28021 from frappe/mergify/bp/version-13-pre-release/pr-28005
fix: Fetch thumbnail from Item master instead of regenerating (backport #28005)
2021-10-20 15:14:30 +05:30
marination
b906cc20ae fix: Move thumbnail updation to different patch
- Thumbnail updation handled via different patch
- create_website_items will only have one purpose
- added progress bar to `create_website_items`
- code cleanup

(cherry picked from commit 348a961b53)
2021-10-20 09:12:33 +00:00
marination
c98421c69a fix: Check if thumbnail column exists in case of table trimming
(cherry picked from commit ac8014e24c)
2021-10-20 09:12:32 +00:00
marination
d7afb9ef65 fix: Get db values as dict when checking for thumbnail in existing web item
(cherry picked from commit 46a5a83789)
2021-10-20 09:12:32 +00:00
marination
a915b9cf72 fix: re-run patch
- Patch will just fetch thumbnails if website items are created, else it will create new website items

(cherry picked from commit 11c498d9e5)
2021-10-20 09:12:32 +00:00
marination
a022e01d3f fix: Fetch thumbnail from Item master instead of regenerating
(cherry picked from commit 94177c0764)
2021-10-20 09:12:31 +00:00
Marica
077026a7ae Merge pull request #28005 from marination/patch-thumbnail-perf
fix: Fetch thumbnail from Item master instead of regenerating
2021-10-20 14:40:57 +05:30
marination
348a961b53 fix: Move thumbnail updation to different patch
- Thumbnail updation handled via different patch
- create_website_items will only have one purpose
- added progress bar to `create_website_items`
- code cleanup
2021-10-20 14:14:13 +05:30
Jannat Patel
3cf5861a8b Merge pull request #28015 from frappe/mergify/bp/version-13-hotfix/pr-27728
fix: Employee Leave Balance report should only consider ledgers of transaction type Leave Allocation (backport #27728)
2021-10-20 13:10:58 +05:30
Jannat Patel
8e9db11c69 Merge pull request #28012 from frappe/mergify/bp/version-13-hotfix/pr-27904
fix: map missing fields in opportunity (backport #27904)
2021-10-20 12:36:46 +05:30
Goh Yan Chang
867cfa04b2 Update employee_leave_balance.py
fix: Employee Leave Balance report showing wrong figures
(cherry picked from commit 632f7848a3)
2021-10-20 06:58:12 +00:00
Goh Yan Chang
50af32f35c Update employee_leave_balance.py
fix: Employee Leave Balance report showing wrong figures
(cherry picked from commit 632f7848a3)
2021-10-20 06:57:51 +00:00
Jannat Patel
6e63dc1360 Merge pull request #28013 from frappe/mergify/bp/version-13-pre-release/pr-27904 2021-10-20 12:24:37 +05:30
Deepesh Garg
944e3d467c fix: Check for supplier name 2021-10-20 12:17:13 +05:30
Deepesh Garg
b7befe49dc fix: Check for other properties 2021-10-20 12:16:22 +05:30
Jannat Patel
8c57394e78 fix: conflicts 2021-10-20 12:14:15 +05:30
Deepesh Garg
f12deae24b fix: Error in TDS computation summary 2021-10-20 12:07:22 +05:30
Jannat Patel
8e2a84e435 Merge pull request #27997 from govindsmenokee/patch-7
fix: Employee filter in YTD and MTD in salary slip
2021-10-20 11:43:55 +05:30
Jannat Patel
698214bd59 fix: removed unused lines 2021-10-20 11:36:00 +05:30
Jannat Patel
873d166a4e fix: conflicts 2021-10-20 11:32:35 +05:30
Jannat Patel
ae948e31ea fix: linters 2021-10-20 11:30:33 +05:30
Jannat Patel
9166d58717 fix: map missing fields in opportunity (#27904)
(cherry picked from commit d81f811349)

# Conflicts:
#	erpnext/crm/doctype/opportunity/opportunity.py
2021-10-20 05:56:59 +00:00
Jannat Patel
2fff5e5cd1 fix: map missing fields in opportunity (#27904)
(cherry picked from commit d81f811349)

# Conflicts:
#	erpnext/crm/doctype/opportunity/opportunity.py
2021-10-20 05:56:37 +00:00
marination
ac8014e24c fix: Check if thumbnail column exists in case of table trimming 2021-10-19 18:50:44 +05:30
marination
46a5a83789 fix: Get db values as dict when checking for thumbnail in existing web item 2021-10-19 18:39:48 +05:30
marination
11c498d9e5 fix: re-run patch
- Patch will just fetch thumbnails if website items are created, else it will create new website items
2021-10-19 18:32:43 +05:30
Deepesh Garg
7895d2a048 Merge pull request #28004 from frappe/mergify/bp/version-13-pre-release/pr-27867
fix: Totals row incorrect value in GL Entry (backport #27867)
2021-10-19 17:50:20 +05:30
marination
94177c0764 fix: Fetch thumbnail from Item master instead of regenerating 2021-10-19 17:31:55 +05:30
Jannat Patel
0a4abff354 Merge branch 'version-13-hotfix' into patch-7 2021-10-19 16:10:51 +05:30
Deepesh Garg
5a06ee9230 fix: Totals row incorrect value in GL Entry (#27867)
(cherry picked from commit ebe68c1a7a)
2021-10-19 09:39:02 +00:00
Deepesh Garg
ebe68c1a7a fix: Totals row incorrect value in GL Entry (#27867) 2021-10-19 15:08:05 +05:30
mergify[bot]
35448886bc Merge pull request #27999 from frappe/mergify/bp/version-13-hotfix/pr-27990
fix: changes in schedules gets overwritten on save (backport #27990)
2021-10-19 14:33:57 +05:30
Noah Jacob
b6609d1649 Merge pull request #27998 from frappe/mergify/bp/version-13-pre-release/pr-27990
fix: changes in schedules gets overwritten on save (backport #27990)
2021-10-19 14:20:44 +05:30
mergify[bot]
3af060c787 fix: TaxJar update - added nexus list, making api call only for nexus (backport #27497) (#27940)
* fix: TaxJar update - nexus, selective api call

(cherry picked from commit b01fe1c3e2)

* fix: sales_tax attribute in api call before submit

(cherry picked from commit 3bb60a439a)

* Update erpnext/erpnext_integrations/taxjar_integration.py

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit 0e527311b9)

* Update erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit 486d7c3a39)

* Update erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit 435a5e4fa3)

* Update erpnext/erpnext_integrations/taxjar_integration.py

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit 11bd42467e)

* fix: Renamed child table doctype, delete taxes for non nexus state

(cherry picked from commit 5c18654113)

* fix: updated patch, add fields only if fields are checked

(cherry picked from commit 54754f4eb8)

# Conflicts:
#	erpnext/patches/v13_0/custom_fields_for_taxjar_integration.py

* fix: patch fix, fields disabling

(cherry picked from commit 0a28fed679)

* fix: using db.exists and get_value instead of get_doc

(cherry picked from commit 8675ca5bdd)

* fix: dt instead of document in set_value query

(cherry picked from commit d3bb920e71)

* minor fixes

(cherry picked from commit 254b20bc09)

* fix: improved on_update method, added validation for tax calculation, sandbox mode checks

(cherry picked from commit 7114659ecc)

* fix: linters fix

(cherry picked from commit 3ece05a9f7)

* fix: patch fix added reload_doctype

(cherry picked from commit eaa3614155)

* fix: patch fixes- force reload doc, check for company

(cherry picked from commit 1b25e69af4)

* fix: 'Taxjar' type fix

(cherry picked from commit ea2038489f)

* fix: Update pacthes.txt

(cherry picked from commit 5d4c919c5c)

* fix: Patch

(cherry picked from commit 2d19e2d54b)

# Conflicts:
#	erpnext/patches.txt

* fix: Move product tax category folder to taxjar settings

(cherry picked from commit bd8cfb2e30)

* Update custom_fields_for_taxjar_integration.py

* fix: conflicts

* fix: linter issues

removed extra line

* fix: patch fix

einvoicing deprecation patch removed

Co-authored-by: Subin Tom <subintom2@gmail.com>
Co-authored-by: Subin Tom <36098155+nemesis189@users.noreply.github.com>
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-19 13:38:50 +05:30
Noah Jacob
9431bb9466 fix: changes in schedules gets overwritten on save
(cherry picked from commit af1b9e100e)
2021-10-19 08:07:42 +00:00
Govind S Menokee
efc292a5dd YTD and MTD Messed up in Salary Slip
The filter for YTD, MTD etc are based on employee name. This seems like an amateur mistake. It should be based on employee id.
2021-10-19 12:49:00 +05:30
mergify[bot]
37088391bb feat: add enabled field in UOM (#27993) (#27996)
(cherry picked from commit 7717b99edb)

Co-authored-by: Himanshu <himanshuwarekar@yahoo.com>
2021-10-19 10:56:33 +05:30
mergify[bot]
fdd9cc76be fix: flaky Org Chart Test (#27971) (#27989)
(cherry picked from commit 8eacaddde7)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-18 11:47:22 +05:30
mergify[bot]
f328b226fb fix: flaky Org Chart Test (#27971) (#27988)
(cherry picked from commit 8eacaddde7)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-18 11:47:12 +05:30
Deepesh Garg
f8348ab681 Merge pull request #27983 from frappe/mergify/bp/version-13-pre-release/pr-27967
fix: Account number and name incorrectly imported using COA importer (backport #27967)
2021-10-18 11:04:39 +05:30
Deepesh Garg
9f71863a6a Merge pull request #27982 from frappe/mergify/bp/version-13-hotfix/pr-27967
fix: Account number and name incorrectly imported using COA importer (backport #27967)
2021-10-18 11:03:51 +05:30
Deepesh Garg
eecfb25c90 Merge pull request #27981 from frappe/mergify/bp/version-13-pre-release/pr-27934
fix: TDS round off not working from second transaction (backport #27934)
2021-10-18 11:03:00 +05:30
Deepesh Garg
c99fe8b57d Merge pull request #27980 from frappe/mergify/bp/version-13-hotfix/pr-27934
fix: TDS round off not working from second transaction (backport #27934)
2021-10-18 11:02:33 +05:30
Deepesh Garg
41a0e12954 Merge pull request #27979 from frappe/mergify/bp/version-13-pre-release/pr-27970
fix (India): Interstate internal transfer invoices not visible in GSTR-1 (backport #27970)
2021-10-18 11:01:06 +05:30
Deepesh Garg
a883f16f31 Merge pull request #27978 from frappe/mergify/bp/version-13-hotfix/pr-27970
fix (India): Interstate internal transfer invoices not visible in GSTR-1 (backport #27970)
2021-10-18 11:00:47 +05:30
Jannat Patel
07a9f16eb5 Merge pull request #27984 from frappe/mergify/bp/version-13-hotfix/pr-27850 2021-10-18 10:35:55 +05:30
Ankush Menat
f0383289d8 Merge pull request #27986 from frappe/mergify/bp/version-13-pre-release/pr-27962
fix: Retain space inside Serial no string while cleaning serial nos (backport #27962)
2021-10-18 10:34:31 +05:30
Jannat Patel
46209023ce Merge pull request #27985 from frappe/mergify/bp/version-13-pre-release/pr-27850 2021-10-18 10:32:48 +05:30
marination
e69bd39cdd test: Include serial no with spaces in it in sanitation test
(cherry picked from commit a9341672cf)
2021-10-18 04:56:11 +00:00
Marica
0fcb3cd918 fix: Use strip instead of lstrip and rstrip
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
(cherry picked from commit 8cf188d9c0)
2021-10-18 04:56:10 +00:00
marination
44ab131792 fix: Retain space inside Serial no string while cleaning serial nos
(cherry picked from commit 41035b0330)
2021-10-18 04:56:10 +00:00
pateljannat
b648d77316 fix: exclude inactive employees from auto attendance
(cherry picked from commit 921b4be348)
2021-10-18 04:35:18 +00:00
pateljannat
acc5cff7ff fix: exclude inactive employees from auto attendance
(cherry picked from commit 921b4be348)
2021-10-18 04:34:53 +00:00
Deepesh Garg
0012f0b2da fix: Account number and name incorrectly import using COA importer
(cherry picked from commit 17a8649500)
2021-10-18 03:47:22 +00:00
Deepesh Garg
f2340b360f fix: Account number and name incorrectly import using COA importer
(cherry picked from commit 17a8649500)
2021-10-18 03:46:59 +00:00
Deepesh Garg
1796f09c0f fix: TDS round off not working from second transaction
(cherry picked from commit b7a08535b5)
2021-10-18 03:24:46 +00:00
Deepesh Garg
64b58b148f fix: TDS round off not working from second transaction
(cherry picked from commit ca0067212d)
2021-10-18 03:24:46 +00:00
Deepesh Garg
9b71e02003 fix: TDS round off not working from second transaction
(cherry picked from commit b7a08535b5)
2021-10-18 03:24:23 +00:00
Deepesh Garg
50e718f508 fix: TDS round off not working from second transaction
(cherry picked from commit ca0067212d)
2021-10-18 03:24:22 +00:00
Deepesh Garg
4415bf9968 fix: Interstate internal transfer invoices not visible in GSTR-1
(cherry picked from commit d9d42b13ab)
2021-10-18 03:23:55 +00:00
Deepesh Garg
289650748c fix: Interstate internal transfer invoices not visible in GSTR-1
(cherry picked from commit d9d42b13ab)
2021-10-18 03:23:31 +00:00
mergify[bot]
268893d5d0 fix: POS Profile payment methods table (#27956) (#27966)
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
(cherry picked from commit f3cf36f613)

Co-authored-by: Subin Tom <36098155+nemesis189@users.noreply.github.com>
2021-10-15 14:32:55 +05:30
Marica
7b4a5e7e64 Merge pull request #27965 from frappe/mergify/bp/version-13-hotfix/pr-27962
fix: Retain space inside Serial no string while cleaning serial nos (backport #27962)
2021-10-14 20:38:20 +05:30
marination
0d1b04326a test: Include serial no with spaces in it in sanitation test
(cherry picked from commit a9341672cf)
2021-10-14 14:48:24 +00:00
Marica
db9f56bee8 fix: Use strip instead of lstrip and rstrip
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
(cherry picked from commit 8cf188d9c0)
2021-10-14 14:48:24 +00:00
marination
2e9d08f8b1 fix: Retain space inside Serial no string while cleaning serial nos
(cherry picked from commit 41035b0330)
2021-10-14 14:48:24 +00:00
mergify[bot]
02ddd5f2b0 fix: remove bad description (#27963) (#27964)
(cherry picked from commit 4437eb0c4b)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-14 20:06:07 +05:30
rohitwaghchaure
1b7d94d70d Merge pull request #27961 from rohitwaghchaure/merge-13-hotfix-to-pre-release-for-13-13
chore: Merge branch 'version-13-hotfix' into 'version-13-pre-release'
2021-10-14 19:17:22 +05:30
Rohit Waghchaure
952c60b3f5 Merge branch 'version-13-hotfix' into 'version-13-pre-release' 2021-10-14 18:31:09 +05:30
rohitwaghchaure
8c33103838 Merge pull request #27958 from frappe/mergify/bp/version-13-hotfix/pr-27954
fix: value_after_depreciation calculation (backport #27954)
2021-10-14 18:25:57 +05:30
mergify[bot]
a8c966eb25 fix: patch to enable scheduled job for reposting (backport #27957)
* fix: patch to enable scheduled job for reposting

(cherry picked from commit efc60ec2b5)

# Conflicts:
#	erpnext/patches.txt

* chore: formatting

(cherry picked from commit 3f97413814)

* Update enable_scheduler_job_for_item_reposting.py

(cherry picked from commit 230a5d4b39)

* fix: resolve conflict

Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2021-10-14 17:31:51 +05:30
Saqib
88b1c1c87e fix: value_after_depreciation calculation (#27954)
(cherry picked from commit 1f70dd6e98)
2021-10-14 10:53:52 +00:00
Marica
771213c415 Merge pull request #27955 from frappe/mergify/bp/version-13-hotfix/pr-27947
fix: Improve error message for Serial No mismatch between SI and DN (backport #27947)
2021-10-14 14:24:54 +05:30
marination
d86f5ec1ba fix: Remove trailing space and line break in translatable string
(cherry picked from commit 60f35ad8a2)
2021-10-14 08:19:54 +00:00
marination
a568fc7924 fix: Improve error message for Serial No mismatch between SI and DN
(cherry picked from commit 646acb6b46)
2021-10-14 08:19:53 +00:00
mergify[bot]
c040256793 fix: cannot add deductions in internal transfer payment entry (backport #27545) (#27930)
* fix: cannot add deductions in internal transfer payment entry

(cherry picked from commit 1b7414e948)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.py

* fix: Update message string

(cherry picked from commit 3b9514d6e1)

# Conflicts:
#	erpnext/accounts/doctype/payment_entry/payment_entry.py

* fix: conflicts

Co-authored-by: Saqib Ansari <nextchamp.saqib@gmail.com>
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-14 12:34:03 +05:30
Chillar Anand
29996ee726 fix(hr): Update expense account after company is updated (#27843) (#27919)
(cherry picked from commit f0c4ea14a9)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-14 11:13:00 +05:30
Deepesh Garg
1120506e11 Merge pull request #27941 from frappe/mergify/bp/version-13-hotfix/pr-27783
fix(Subscription): reorder updation of end date (backport #27783)
2021-10-13 16:56:07 +05:30
mergify[bot]
e64751e3a2 fix: not authorized to update entries after freezing accounts (backport #27937)
* fix: not authorized to update entries after freezing accounts (#27937)

* fix: not authorized to update entries after freezing accounts

* fix: Add test case

* fix(patch): patched to requeue failed reposts(check_freezing_date)

* chore: misc fixes

Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
Co-authored-by: Ankush Menat <ankushmenat@gmail.com>
(cherry picked from commit 2bb383b178)

# Conflicts:
#	erpnext/patches.txt

* fix: resolve conflict

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-13 16:41:21 +05:30
Himanshu
bf47c6836e Update subscription.py
(cherry picked from commit 44306bd0e5)
2021-10-13 09:52:21 +00:00
hrwx
e80192e2da fix: create past invoices
(cherry picked from commit ae657c7e4e)
2021-10-13 09:52:21 +00:00
Sagar Vora
b2f1b02e34 test: use test_dependencies instead of duplication
(cherry picked from commit 656015d99d)
2021-10-13 09:52:20 +00:00
Sagar Vora
ed090f2e3e fix: remove newline
(cherry picked from commit fc375c5bde)
2021-10-13 09:52:20 +00:00
hrwx
d796172249 fix: reorder updation of end date
(cherry picked from commit 0f03b19109)
2021-10-13 09:52:20 +00:00
Deepesh Garg
ff9f6366ad Merge pull request #27935 from frappe/mergify/bp/version-13-hotfix/pr-27907
feat: HSN based tax breakup table check in GST Settings  (backport #27907)
2021-10-13 12:56:00 +05:30
Deepesh Garg
b8683d5532 Merge pull request #27925 from frappe/mergify/bp/version-13-hotfix/pr-27758
perf: Add indexes in stock queries and speed up bin updation (backport #27758)
2021-10-13 12:08:38 +05:30
Subin Tom
4a156cdc2e added new section in gst settings page
(cherry picked from commit fc4facc5dc)
2021-10-13 06:38:27 +00:00
Subin Tom
771b076448 feat: HSN wise tax breakup check in GST Settings
(cherry picked from commit 530de12b07)
2021-10-13 06:38:26 +00:00
mergify[bot]
e6346ac982 fix: minor ux fixes in Sales & Purchase Invoice (backport #27927) (#27932)
* fix: keeping sections consistent across sales & purchase invoice

(cherry picked from commit 2bc1ca993a)

* fix: set collapsible & print hide

(cherry picked from commit d181cc42a1)

Co-authored-by: Anuja Pawar <anuja.pawar20@gmail.com>
2021-10-13 11:01:21 +05:30
Faris Ansari
666e8cd076 perf: Optimize get_attribute_filters (#26729)
* perf: Optimize get_attribute_filters

* fix: handle when filter attributes are undefined

* chore: unused imports

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-12 23:43:26 +05:30
Ankush Menat
547e173fe0 ci: rule to fail PRs that add a new manual commit (#27928)
Manual commits are frequent source of bugs, confusions or undefined
behaviour.

All new manual commits should be explcitly ignored with explanation on
why it's added. This will only fail for new additions. Existing ones
need to be cleaned up manually.

(cherry picked from commit 06b426e9c3)
2021-10-12 23:05:09 +05:30
mergify[bot]
37bd0ecf87 fix: force reload custom field doctype (#27909) (#27910)
custom_field.json has the same modified key in both versions but not the same content. This can happen again if something is backported, safe solution is to force reload.

(cherry picked from commit ad444153cc)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-12 20:38:09 +05:30
Marica
8244980d79 Merge pull request #27924 from marination/item-configure-empty-popup
fix: Item Variant selection empty popup on website
2021-10-12 20:32:18 +05:30
marination
f3650b4f9d fix: Merge conflicts with e-commerce 2021-10-12 20:29:13 +05:30
marination
6b8dad9454 fix: Sider, Linter
- Moved return to next line
- Space between function import and body

(cherry picked from commit a780f78f38)
2021-10-12 14:55:08 +00:00
marination
1590ac3ec7 fix: Avoid automatic customer creation on website user login
(cherry picked from commit d824a90fac)

# Conflicts:
#	erpnext/e_commerce/shopping_cart/utils.py
2021-10-12 14:55:08 +00:00
Deepesh Garg
10b239ec50 perf: Add indexes in stock queries and speed up bin updation #27758
perf: Add indexes in stock queries and speed up bin updation
(cherry picked from commit 6f107da165)
2021-10-12 14:46:26 +00:00
marination
c9c4a9995b fix: Item Variant selection empty popup on website
- pass item_code instead of website item name to fetch attributes
2021-10-12 19:56:12 +05:30
Ankush Menat
b6dc71679e fix: remove transaction commit from tests
(cherry picked from commit 8d69ec72a6)
2021-10-12 16:41:48 +05:30
Ankush Menat
5bdb6041b9 refactor: rollback after full test
(cherry picked from commit acdb26a4bb)
2021-10-12 16:41:48 +05:30
Ankush Menat
89828defc5 test: add custom TestCase class and use in stock
(cherry picked from commit 06fa35a9c1)
2021-10-12 16:41:48 +05:30
Deepesh Garg
816236b587 Merge pull request #27918 from frappe/mergify/bp/version-13-hotfix/pr-27884
fix: patch fails if accounts are frozen (backport #27884)
2021-10-12 15:04:01 +05:30
Deepesh Garg
69f17721ef Merge pull request #27917 from frappe/mergify/bp/version-13-hotfix/pr-27896
fix: Status check for closed loans (backport #27896)
2021-10-12 15:03:31 +05:30
Afshan
125bb1f99a Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27884 2021-10-12 14:32:36 +05:30
mergify[bot]
6f786b42a9 fix: add cost center in gl entry for advance payment entry (#27840) (#27915)
(cherry picked from commit 569dc5f6b1)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-12 14:31:50 +05:30
Saqib Ansari
fed80177de fix: rollback on exception
(cherry picked from commit c103f72fad)
2021-10-12 08:15:17 +00:00
Saqib Ansari
2ce36d1edc feat: handle exceptions
(cherry picked from commit 353ad5f6ff)
2021-10-12 08:15:17 +00:00
Saqib Ansari
7e44c30404 fix: patch fails if accounts are frozen
(cherry picked from commit b0aa4a6e1c)
2021-10-12 08:15:16 +00:00
Deepesh Garg
47ced6810f fix: Linting issues
(cherry picked from commit af14ba43de)
2021-10-12 08:11:47 +00:00
Deepesh Garg
6c3f5687f2 fix: Incorrect maximum loan amount update
(cherry picked from commit 8355af6dcf)
2021-10-12 08:11:47 +00:00
Deepesh Garg
1b632b683f fix: Status check for closed loans
(cherry picked from commit 3337ae120c)
2021-10-12 08:11:46 +00:00
mergify[bot]
c5660e8511 Merge pull request #27906 from Anuja-pawar/accounts-settings (#27912)
fix(Accounts Settings): Update label

(cherry picked from commit e1967870a9)

Co-authored-by: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com>
2021-10-12 12:23:53 +05:30
mergify[bot]
c4338d184e fix(accounts): Fix issue with fetching loyalty point entries (#27892) (#27913)
(cherry picked from commit 401e22fb8d)

Co-authored-by: Chillar Anand <chillar@avilpage.com>
2021-10-12 12:23:32 +05:30
Noah Jacob
d598a61556 Merge pull request #27901 from frappe/mergify/bp/version-13-hotfix/pr-27800
refactor: updated buying onboarding tours. (backport #27800)
2021-10-11 16:33:59 +05:30
Noah Jacob
d262d0ac27 refactor: updated onboarding cards and tours
(cherry picked from commit f5e0cad6a1)
2021-10-11 10:04:40 +00:00
mergify[bot]
7dc2f95932 fix: v12 migrate error - unknown column ‘mandatory_depends_on’ (backport #27897) (#27900)
* fix: v12 migrate error - unknown column ‘mandatory_depends_on’ (#27897)

* fix: v12 doesn't have mandatory_depends_on field

* fix: move update_vehicle_no_reqd_condition to v13

* fix: move update_vehicle_no_reqd_condition to v13

* fix: file name missing .py

* refactor!: add back empty line

* fix: linters issue

(cherry picked from commit 7acdcc70ad)

# Conflicts:
#	erpnext/patches.txt

* fix: resolve conflicts

Co-authored-by: Dany Robert <rtdany10@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-11 10:02:31 +00:00
rohitwaghchaure
cf87c9138e Merge pull request #27898 from frappe/mergify/bp/version-13-hotfix/pr-27863
fix: consolidated report not consider company currency (backport #27863)
2021-10-11 14:07:51 +05:30
Rohit Waghchaure
1a42f82d14 fix: opening balance to calculate 'Unclosed Fiscal Years Profit / Loss (Credit)'
(cherry picked from commit 19d14da0d4)
2021-10-11 08:37:27 +00:00
Rohit Waghchaure
2c5a0bff47 fix: consolidated report not consider company currency
(cherry picked from commit dc4206428d)
2021-10-11 08:37:26 +00:00
mergify[bot]
a831e6b552 fix: bom item query (backport #27890) (#27894)
* fix: bom item query #27890

fix: bom item query
(cherry picked from commit 0a3dd3e954)

# Conflicts:
#	erpnext/manufacturing/doctype/bom/test_bom.py

* fix: resolve conflict

* chore: unused imports

[skip ci]

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-11 12:45:24 +05:30
ChillarAnand
f844c36ab2 fix(CI): Use bugbear instead of flake8-mutable
(cherry picked from commit 4dc17a856e)
2021-10-11 11:23:22 +05:30
mergify[bot]
091c2f3023 fix(perf): index creation on voucher_detail_no (#27866) (#27875)
voucher_detail_no is supposed to have an index, it was added on
on_doctype_update function of table, however this function is only
called if DocType itself is updated and `on_update` is called on
DocType. Stock ledger Entry doctype hasn't changed since addition of
this index in function.

Before: Lack of this index was causing full table scan in
get_future_sle_to_fix function. (~50 seconds in a reposting job)

After: Single row is fetched (~0.5 second in full reposting job)

Learnings:
1. Add simple indexes via doctype only
2. For complex indexes always change doctype.json file for it to take
   effect.

(cherry picked from commit 6019f60d0a)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-08 17:19:41 +05:30
mergify[bot]
119c2f01e1 fix(perf): index creation on voucher_detail_no (#27866) (#27876)
voucher_detail_no is supposed to have an index, it was added on
on_doctype_update function of table, however this function is only
called if DocType itself is updated and `on_update` is called on
DocType. Stock ledger Entry doctype hasn't changed since addition of
this index in function.

Before: Lack of this index was causing full table scan in
get_future_sle_to_fix function. (~50 seconds in a reposting job)

After: Single row is fetched (~0.5 second in full reposting job)

Learnings:
1. Add simple indexes via doctype only
2. For complex indexes always change doctype.json file for it to take
   effect.

(cherry picked from commit 6019f60d0a)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-08 17:19:34 +05:30
gavin
40aac908d1 fix: Ignore mandatory fields if exist (#27871)
The goal of this fix is to not break the patch in case of customizations
In this particular case, it's regarding a customized Note DocType with
multiple custom mandatory fields
2021-10-08 15:10:03 +05:30
mergify[bot]
4e6d588ae1 fix: remove readonly from billing address (#27873)
(cherry picked from commit 41fefa356f)

Co-authored-by: 18alantom <2.alan.tom@gmail.com>
2021-10-08 15:08:45 +05:30
mergify[bot]
504f2f06d3 fix: Salary Slip Label fixes (backport #27865) (#27870)
* fix: Salary Slip Label fixes (#27865)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
(cherry picked from commit d3d4a3da62)

# Conflicts:
#	erpnext/payroll/doctype/salary_slip/salary_slip.json

* fix: conflicts

Co-authored-by: yadavyk <32797974+yadavyk@users.noreply.github.com>
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-08 14:16:12 +05:30
mergify[bot]
d96fd60878 fix: update dead links in help_links.js (#27860) (#27868)
(cherry picked from commit 90a249527d)

Co-authored-by: Kenneth Sequeira <33246109+kennethsequeira@users.noreply.github.com>
2021-10-08 13:31:07 +05:30
Deepesh Garg
d9a219850a fix: SO delivery Date not getting set via data import (#27862)
* fix: SO delivery Date not getting set via data import

* fix: logic to add delivery dates

* fix: linting issue

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Co-authored-by: Afshan <afshan13k@gmail.com>
2021-10-08 12:38:40 +05:30
mergify[bot]
cb6d884058 fix(Payment Reconciliation): minor ux fixes (#27779) (#27859)
* fix: minor fixes

* fix: Linters check

* fix: sider check

* fix: kept unallocated payment amount hidden in allocation

* fix: removed Add row button from the tables (redundant)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
(cherry picked from commit 5cc3ea0aa7)

Co-authored-by: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com>
2021-10-07 22:47:05 +05:30
mergify[bot]
4102f799dc fix: trim sales invoice custom field lengths (backport #27665) (#27750)
* fix: trim sales invoice custom field lengths

(cherry picked from commit a7df4227da)

* patch: trim sales invoice custom field lengths

(cherry picked from commit f1fcb385f5)

# Conflicts:
#	erpnext/patches.txt

* fix: do not set length for date field

(cherry picked from commit 83cc597594)

* fix: merge conflicts

Co-authored-by: Saqib Ansari <nextchamp.saqib@gmail.com>
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-07 20:59:07 +05:30
Subin Tom
3c53c5b660 fix: cancelled sales invoices are considered in billed quantity calculation (#27845)
Co-authored-by: Saqib Ansari <nextchamp.saqib@gmail.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-07 20:36:00 +05:30
mergify[bot]
0a4b3d8129 fix: help links for purchase cycle and JV (#27856) (#27858)
(cherry picked from commit 07c680d7cc)

Co-authored-by: Kenneth Sequeira <33246109+kennethsequeira@users.noreply.github.com>
2021-10-07 20:29:28 +05:30
mergify[bot]
bad489426a feat: (Stock Reco) Ignore Empty Stock while fetching items from warehouse (#27848)
- Added checkbox to `Fetch Items from Warehouse` dialog to ignore empty stock
- fix: Items fetched twice due to Item Defaults
- Improved code readability

(cherry picked from commit 533ee9a401)

Co-authored-by: marination <maricadsouza221197@gmail.com>
2021-10-07 20:28:08 +05:30
mergify[bot]
729e29d268 fix: update help links for Sales Invoice page (#27853) (#27854)
(cherry picked from commit 646fd29f0e)

Co-authored-by: Kenneth Sequeira <33246109+kennethsequeira@users.noreply.github.com>
2021-10-07 18:42:06 +05:30
rohitwaghchaure
8108d4761b Merge pull request #27852 from frappe/mergify/bp/version-13-hotfix/pr-27851
feat: option to set the width for the multi-select dialog box (backport #27851)
2021-10-07 17:39:20 +05:30
Rohit Waghchaure
00cb04df84 feat: option to set the width for the multi-select dialog box
(cherry picked from commit 69ffddf747)
2021-10-07 12:08:58 +00:00
mergify[bot]
dd0cefbeb9 refactor: Clean up mutable defaults and add CI check (#27828) (#27841)
* refactor: Clean up mutable defaults and add CI check

(cherry picked from commit 772d4753e7)

Co-authored-by: Chillar Anand <chillar@avilpage.com>
2021-10-07 09:57:35 +00:00
Rohit Waghchaure
d11c215f85 Merge branch 'version-13-pre-release' into version-13 2021-10-07 11:35:31 +05:30
Rohit Waghchaure
5ea5bfad3d bumped to version 13.12.1 2021-10-07 11:55:31 +05:50
Anoop
4da5cb36e7 Merge pull request #27812 from akurungadam/fix-appointment-slots
fix(healthcare): Availability slots display, disabled Practitioner Schedule
2021-10-07 08:45:56 +05:30
mergify[bot]
56b58cbeea fix: use ceil in case of whole uoms for reorder qty (#27834) (#27838)
* fix: use ceil in case of whole uoms for reorder qty

* fix: cache uom query

(cherry picked from commit d4b2471cea)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-10-06 18:54:22 +05:30
Marica
cd87931cee Merge pull request #27833 from frappe/mergify/bp/version-13-pre-release/pr-27713
fix: Maintenance Schedule child table status for legacy data (backport #27713)
2021-10-06 14:08:15 +05:30
Marica
355ae1fca6 Merge branch 'version-13-pre-release' into mergify/bp/version-13-pre-release/pr-27713 2021-10-06 13:42:46 +05:30
mergify[bot]
91baa22d59 fix: remove stale doctypes and add msg for ecommerce refactor (bp #27700)
(cherry picked from commit 6d99bb5ce6)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-06 13:37:26 +05:30
marination
af57e1e299 fix: reload doc in patch
(cherry picked from commit 6b38778dcb)
2021-10-06 07:57:22 +00:00
marination
1d3ba46107 fix: Add patch to patches.txt
(cherry picked from commit 7c47f36a4c)
2021-10-06 07:57:22 +00:00
Marica
65a590ced1 fix: Maintenance Schedule child table status for legacy data (#27554)
* fix: Maintenance Schedule child table status for legacy data

* fix: Include legacy draft schedules in patch

* fix: Pre-commit formatting

(cherry picked from commit cc143bca0d)
(cherry picked from commit 6ce2111b6d)
2021-10-06 07:57:21 +00:00
Marica
1a68e10742 Merge pull request #27829 from frappe/mergify/bp/version-13-pre-release/pr-27715
fix: Batch scans get overwritten on the same row (backport #27668) (backport #27715)
2021-10-06 12:57:39 +05:30
Marica
71f676eedd Merge pull request #27764 from frappe/mergify/bp/version-13-hotfix/pr-27661
refactor: fetching of account balance in chart of accounts (backport #27661)
2021-10-06 12:56:10 +05:30
mergify[bot]
4fe827e86b Merge pull request #27715 from frappe/mergify/bp/version-13-hotfix/pr-27668
fix: Batch scans get overwritten on the same row (backport #27668)
(cherry picked from commit 15c9c08261)
2021-10-06 07:13:00 +00:00
Deepesh Garg
f573840c9f Merge pull request #27801 from frappe/mergify/bp/version-13-pre-release/pr-27524
fix: Tax breakup based on items, missing GST fields (backport #27524)
2021-10-06 09:33:30 +05:30
mergify[bot]
e57037b4cf ci: fail build if asset bundling fails (#27820) (#27823)
(cherry picked from commit 35e30bdcaf)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-05 23:59:47 +05:30
Deepesh Garg
51b2fcc8ef fix: Update setup.py 2021-10-05 21:05:12 +05:30
Deepesh Garg
ff062d501f fix: Update patches.txt 2021-10-05 21:03:40 +05:30
mergify[bot]
2cbd5a9fcf fix: removed redundant piece of code (#27817) (#27821)
(cherry picked from commit cec66d2d10)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-05 19:26:58 +05:30
Noah Jacob
47a7eeca54 Merge pull request #27814 from frappe/mergify/bp/version-13-hotfix/pr-27813
fix: ignore random periodicity in validations (backport #27813)
2021-10-05 17:30:00 +05:30
Ankush Menat
62bbf0fe45 fix: ignore random periodicity in validations
(cherry picked from commit 3d3655ed73)
2021-10-05 11:28:34 +00:00
Marica
ae8c1ae311 Merge pull request #27803 from frappe/mergify/bp/version-13-hotfix/pr-27660
fix: tax rate being overridden in case of 0.00 (backport #27660)
2021-10-05 16:44:16 +05:30
Deepesh Garg
8f5ab94b70 Merge pull request #27792 from deepeshgarg007/pre-release-fixes
fix: COA Importer showing blank validations
2021-10-05 15:18:04 +05:30
Deepesh Garg
9507b2d752 fix: Use get_list instead of get_all to avoid perm issues 2021-10-05 14:51:35 +05:30
mergify[bot]
7e018f94ce fix: batch_no not mapped from PR to Stock Entry (#27804)
(cherry picked from commit 9613af6c4e)

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-10-05 14:39:36 +05:30
Ankush Menat
2cfafede44 fix(ux): use toast instead of popup 2021-10-05 14:27:09 +05:30
Ankush Menat
df1f8fddf6 fix: using DN for transfer w/o internal customer (#27798)
This used to be work before though not "advertised", since a lot of
users have started using it as feature, it can't be broken now.
2021-10-05 14:21:27 +05:30
Dany Robert
a17fed9cd9 fix: return tax rate since fetch is removed
(cherry picked from commit 2b4959fb3b)
2021-10-05 08:45:24 +00:00
Dany Robert
d8479a41e5 fix: tax rate being overridden in case of 0.00
Tax rate could be different for different expenses.
Therefore, rate is kept as 0.00 and tax amount entered manually.
But fetching used to override the rate(upon saving) and mess up the amount.

(cherry picked from commit 5ce6a4c107)
2021-10-05 08:45:23 +00:00
Subin Tom
b1244df045 fix: Tax breakup based on items, missing GST fields (#27524)
* fix: Tax breakup based on items

* fix: added gst fields,warehouse validation to pos inv,patch

* fix: tax breakup test fix, eway bill hsn fix

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit d49346ac45)

# Conflicts:
#	erpnext/patches.txt
#	erpnext/regional/india/setup.py
2021-10-05 08:44:31 +00:00
Deepesh Garg
d2f5d31f98 Merge pull request #27559 from frappe-pr-bot/backport/version-13-hotfix/27524
fix: Tax breakup based on items, missing GST fields
2021-10-05 14:13:50 +05:30
Deepesh Garg
44ee44dec5 Merge pull request #27786 from frappe/mergify/bp/version-13-hotfix/pr-27785
fix: Delete linked Transaction Deletion Record docs on deleting company (backport #27785)
2021-10-05 14:09:16 +05:30
mergify[bot]
bebd77c27d fix: add (uom, brand) Item details in an Item Price (#27561) (#27795)
* fix: add (uom, brand) and update (uom) Item details in an Item Price

* fix: order of query interpolation args

Co-authored-by: Marica <maricadsouza221197@gmail.com>

* fix: named interpolation, remove item price

* fix: sql error

Co-authored-by: Marica <maricadsouza221197@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
(cherry picked from commit 7da777880b)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-10-05 13:28:43 +05:30
Afshan
0c55a98190 Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27785 2021-10-05 13:26:47 +05:30
mergify[bot]
32d72fdecb fix: Only calculate first_respone_time if SLA is set (#27789) (#27793)
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
(cherry picked from commit ad03eb25df)

Co-authored-by: Ganga Manoj <ganga.manoj98@gmail.com>
2021-10-05 12:49:06 +05:30
mergify[bot]
046ec928e0 fix: Display appropriate message if different Payment Terms are used in PE and its Payment References (#27763)
(cherry picked from commit 9f14695743)

Co-authored-by: GangaManoj <ganga.manoj98@gmail.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-10-05 12:21:21 +05:30
Deepesh Garg
0660d6ed01 fix: COA Importer showing blank validations 2021-10-05 12:20:14 +05:30
Afshan
877820b902 Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27785 2021-10-05 11:50:25 +05:30
mergify[bot]
ab0e381cfc fix(asset): expected value after useful life validation (#27539) (#27790)
(cherry picked from commit 065a2ce983)

Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-10-05 11:47:56 +05:30
Saqib
5e34cdf00f Merge branch 'version-13-hotfix' into mergify/bp/version-13-hotfix/pr-27661 2021-10-05 11:34:02 +05:30
GangaManoj
4ecb798585 fix: Delete linked Transaction Deletion Record docs on deleting company
(cherry picked from commit 38c7e42f0c)
2021-10-05 05:19:37 +00:00
mergify[bot]
91d269fe1a fix: set item uom as stock_uom if it isn't set (#27623) (#27780)
* fix: set item uom as stock_uom if it isn't set

(cherry picked from commit 5c372202d5)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-10-04 22:41:12 +05:30
mergify[bot]
4535a9415f ci(Mergify): configuration update (#27777) (#27778)
Signed-off-by: Ankush Menat <me@ankush.dev>
(cherry picked from commit 4159361d52)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-04 18:10:52 +05:30
Sagar Vora
e17713c9d6 fix: multiple fixes to timesheets (#27775) 2021-10-04 17:08:50 +05:30
mergify[bot]
21a5498d5d fix: Merge "Accounting Ledger" and "Accounts Receivable" in "View" button (#27769) (#27771)
* fix: Added a new button "View" and merged "Accounting Ledger" and "Accounts Receivable" into it

* fix: sider issues

* chore: dead code

(cherry picked from commit b483f173a6)

Co-authored-by: Komal-Saraf0609 <81952590+Komal-Saraf0609@users.noreply.github.com>
2021-10-04 16:06:55 +05:30
Saqib
c0b17edbbf perf: fetching of account balance in chart of accounts (#27661)
(cherry picked from commit 9051735529)
2021-10-04 06:15:34 +00:00
Marica
e9ed379b57 Merge pull request #27743 from frappe/mergify/bp/version-13-hotfix/pr-27611
fix: Hero Slider Control & Alignment fixes (backport #27611)
2021-10-03 14:29:18 +05:30
Marica
4d0d642db7 Merge pull request #27720 from marination/e-comm-web-item-name-thumbnail-fix
fix: Website Items with same Item name unhandled, thumbnails missing
2021-10-03 14:26:20 +05:30
Deepesh Garg
f02438eb54 Merge pull request #27712 from deepeshgarg007/internal_transfer_check_fix
fix(India): Internal transfer check fix
2021-10-03 13:38:51 +05:30
Marica
62fa1f0305 Merge branch 'version-13-hotfix' into e-comm-web-item-name-thumbnail-fix 2021-10-03 13:30:50 +05:30
marination
77d4849ce8 fix: Pre-commit formatting 2021-10-03 13:30:02 +05:30
Deepesh Garg
fe4df3a14a Merge pull request #27748 from deepeshgarg007/yet_chart_of_accounts_importer_fixes
fix: Chart Of Accounts import button not visible
2021-10-02 21:39:07 +05:30
Deepesh Garg
ff570f48a0 fix: Linting issues 2021-10-02 20:46:20 +05:30
Deepesh Garg
e4b89d2fcd fix: Remove unwanted comments 2021-10-02 20:37:15 +05:30
Deepesh Garg
3529622a0d fix: Chart Of Accounts import button not visible 2021-10-02 20:35:11 +05:30
Shariq Ansari
8f98238114 chore: linter fix
(cherry picked from commit 18918e1b4f)
2021-10-02 11:38:31 +00:00
Shariq Ansari
86e3adf344 fix: Fixed alignment of Title, Subtitle, Action Button
(cherry picked from commit 0de735f20b)
2021-10-02 11:38:31 +00:00
Shariq Ansari
d6152df3b4 fix: Creating unique hash for slider id instead of slider name
(cherry picked from commit 3e8e6ac4e2)
2021-10-02 11:38:30 +00:00
Anurag Mishra
4837238f3d feat(HR): Some Enhancements and Onboarding (#25741)
* feat: Hr settings restructure

* feat: remove validation and make As warning

* feat: made leave policy Assignment feild read only

* feat: send leave Notification via 'Notification'

* patch: for field name change

* feat: removed defaults value for removed field

* feat: removed leave Notification fields

* feat: better label and description

* feat: Hr Module onboarding and Onboarding slides

* fix: sider, test, translations

* chore: remove unnecessary code formatting changes

* refactor: HR Onboarding

* refactor: HR Settings

* revert: Notification changes

* chore: remove unnecessary descriptions from leave type

* fix: linter issues

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-02 12:34:21 +05:30
mergify[bot]
e4f12f0458 fix: update variant qty in BOM, Create Work Order dialog (#27686) (#27732)
(cherry picked from commit ece446ffe5)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-10-01 23:21:08 +05:30
mergify[bot]
23431cf261 fix: option to limit reposting in certain timeslot (#27725) (#27726)
(cherry picked from commit a04f9c904e)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-01 13:56:00 +05:30
Anurag Mishra
57e66f958c feat: Tracking Multi-round interview (#25482)
* feat: Tracking Multi-round interview

* fix: releted to scheduler event and formating

* fix: job applicant UI/UX and conflicts

* test: Interview Round

* fix(test): Employee referral, Employee Onboarding, Job Offer

* fix: sider

* feat: set default value in Hr settings

* feat: added validation for designation

* test: Interview

* test: Added validatiolns for skill

* test: Interview feedback

* fix: sider

* fix: remove unnecessary validations and form label cleanups

* chore: clean-up Interview Round and Interview Type doctype

* fix: remove redundant Rating Value, only keep Rating

* fix: update interview details on feedback submission

- make interview feedback submission dialog minimizable

* fix: show submit feedback button only if feedback doesn't exist

* refactor: Interview and Feedback statuses and workflow

* fix(HR Settings): clean up interview settings

* refactor: Interview

* refactor: Interview Feedback, remove unnecessary validations

* chore: update notification messages

* chore: remove unnecessary formatting changes in attendance list and leave application

* refactor: Job Applicant to Interview mapping

* chore: sorted imports

* chore: sorted imports

* fix: sider issues

* fix: linter issues

* fix: sider issues

* fix: tests

* fix: sorted imports

* fix: tests, sider

* fix: therapy plan test

* fix: sider issues

* feat: Include From Time and To Time fields in Interview for cleaner data

* feat: Interview Calendar

* fix: allow renaming masters

* fix: add more fields to list view and standard filter

* fix: validate overlapping interviews

* fix: update tests

* fix: linter issues

* refactor: replace reminder messages with Email Templates

* fix: sider issues

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-10-01 00:10:47 +05:30
mergify[bot]
05374cb8b2 fix(Org Chart): use attribute selectors instead of ID selector for node IDs with special characters (#27717) (#27718)
* fix(Org Chart): use attribute selectors instead of ID selector for node IDs with special chars

* fix: UI tests

(cherry picked from commit 9e08229b7b)

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-09-30 18:45:22 +05:30
marination
36b519c962 fix: Website Items with same Item name unhandled, thumbnails missing
- Use naming series for Website Item. There could be two items with same name and different item code
- Fix: Website Item Page view breaks if cart is disabled
- Fix: thumbnails not created for Website Items after patch
- Fix: ‘Request for Quote’ button & cart summary not visible if checkout is disabled
2021-09-30 18:34:26 +05:30
mergify[bot]
15c9c08261 Merge pull request #27715 from frappe/mergify/bp/version-13-hotfix/pr-27668
fix: Batch scans get overwritten on the same row (backport #27668)
2021-09-30 16:34:11 +05:30
Marica
5d1de91b68 Merge pull request #27713 from frappe-pr-bot/backport/version-13-hotfix/27554
fix: Maintenance Schedule child table status for legacy data
2021-09-30 15:57:27 +05:30
Marica
cf6e10ac7b Merge branch 'version-13-hotfix' into backport/version-13-hotfix/27554 2021-09-30 15:55:04 +05:30
Ankush Menat
6d99bb5ce6 fix: remove stale doctypes and add msg for ecommerce refactor (#27700) 2021-09-30 15:49:26 +05:30
marination
6b38778dcb fix: reload doc in patch 2021-09-30 14:55:57 +05:30
marination
7c47f36a4c fix: Add patch to patches.txt 2021-09-30 14:18:35 +05:30
Marica
6ce2111b6d fix: Maintenance Schedule child table status for legacy data (#27554)
* fix: Maintenance Schedule child table status for legacy data

* fix: Include legacy draft schedules in patch

* fix: Pre-commit formatting

(cherry picked from commit cc143bca0d)
2021-09-30 08:39:55 +00:00
Deepesh Garg
f0af24fc6d fix(India): Internal transfer check fix 2021-09-30 13:28:53 +05:30
Deepesh Garg
6eb9a114be Merge branch 'version-13-hotfix' into backport/version-13-hotfix/27524 2021-09-27 14:55:32 +05:30
Subin Tom
8c01ae952b conflict fixes 2021-09-17 20:18:39 +05:30
Subin Tom
e8cf32e1c8 fixing conflicts 2021-09-17 20:16:10 +05:30
Subin Tom
8dfdab9dc1 fix: Tax breakup based on items, missing GST fields (#27524)
* fix: Tax breakup based on items

* fix: added gst fields,warehouse validation to pos inv,patch

* fix: tax breakup test fix, eway bill hsn fix

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
(cherry picked from commit d49346ac45)

# Conflicts:
#	erpnext/patches.txt
#	erpnext/regional/india/setup.py
2021-09-17 05:21:40 +00:00
349 changed files with 7316 additions and 2199 deletions

View File

@@ -1,6 +1,8 @@
[flake8]
ignore =
B007,
B009,
B010,
B950,
E101,
E111,

View File

@@ -1,38 +0,0 @@
# Semgrep linting
## What is semgrep?
Semgrep or "semantic grep" is language agnostic static analysis tool. In simple terms semgrep is syntax-aware `grep`, so unlike regex it doesn't get confused by different ways of writing same thing or whitespaces or code split in multiple lines etc.
Example:
To check if a translate function is using f-string or not the regex would be `r"_\(\s*f[\"']"` while equivalent rule in semgrep would be `_(f"...")`. As semgrep knows grammer of language it takes care of unnecessary whitespace, type of quotation marks etc.
You can read more such examples in `.github/helper/semgrep_rules` directory.
# Why/when to use this?
We want to maintain quality of contributions, at the same time remembering all the good practices can be pain to deal with while evaluating contributions. Using semgrep if you can translate "best practice" into a rule then it can automate the task for us.
## Running locally
Install semgrep using homebrew `brew install semgrep` or pip `pip install semgrep`.
To run locally use following command:
`semgrep --config=.github/helper/semgrep_rules [file/folder names]`
## Testing
semgrep allows testing the tests. Refer to this page: https://semgrep.dev/docs/writing-rules/testing-rules/
When writing new rules you should write few positive and few negative cases as shown in the guide and current tests.
To run current tests: `semgrep --test --test-ignore-todo .github/helper/semgrep_rules`
## Reference
If you are new to Semgrep read following pages to get started on writing/modifying rules:
- https://semgrep.dev/docs/getting-started/
- https://semgrep.dev/docs/writing-rules/rule-syntax
- https://semgrep.dev/docs/writing-rules/pattern-examples/
- https://semgrep.dev/docs/writing-rules/rule-ideas/#common-use-cases

View File

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

View File

@@ -1,34 +0,0 @@
rules:
- id: frappe-missing-translate-function-in-report-python
paths:
include:
- "**/report"
exclude:
- "**/regional"
pattern-either:
- patterns:
- pattern: |
{..., "label": "...", ...}
- pattern-not: |
{..., "label": _("..."), ...}
- patterns:
- pattern: dict(..., label="...", ...)
- pattern-not: dict(..., label=_("..."), ...)
message: |
All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations
languages: [python]
severity: ERROR
- id: frappe-translated-values-in-business-logic
paths:
include:
- "**/report"
patterns:
- pattern-inside: |
{..., filters: [...], ...}
- pattern: |
{..., options: [..., __("..."), ...], ...}
message: |
Using translated values in options field will require you to translate the values while comparing in business logic. Instead of passing translated labels provide objects that contain both label and value. e.g. { label: __("Option value"), value: "Option value"}
languages: [javascript]
severity: ERROR

View File

@@ -1,6 +0,0 @@
def function_name(input):
# ruleid: frappe-codeinjection-eval
eval(input)
# ok: frappe-codeinjection-eval
eval("1 + 1")

View File

@@ -1,10 +0,0 @@
rules:
- id: frappe-codeinjection-eval
patterns:
- pattern-not: eval("...")
- pattern: eval(...)
message: |
Detected the use of eval(). eval() can be dangerous if used to evaluate
dynamic content. Avoid it or use safe_eval().
languages: [python]
severity: ERROR

View File

@@ -1,44 +0,0 @@
// ruleid: frappe-translation-empty-string
__("")
// ruleid: frappe-translation-empty-string
__('')
// ok: frappe-translation-js-formatting
__('Welcome {0}, get started with ERPNext in just a few clicks.', [full_name]);
// ruleid: frappe-translation-js-formatting
__(`Welcome ${full_name}, get started with ERPNext in just a few clicks.`);
// ok: frappe-translation-js-formatting
__('This is fine');
// ok: frappe-translation-trailing-spaces
__('This is fine');
// ruleid: frappe-translation-trailing-spaces
__(' this is not ok ');
// ruleid: frappe-translation-trailing-spaces
__('this is not ok ');
// ruleid: frappe-translation-trailing-spaces
__(' this is not ok');
// ok: frappe-translation-js-splitting
__('You have {0} subscribers in your mailing list.', [subscribers.length])
// todoruleid: frappe-translation-js-splitting
__('You have') + subscribers.length + __('subscribers in your mailing list.')
// ruleid: frappe-translation-js-splitting
__('You have' + 'subscribers in your mailing list.')
// ruleid: frappe-translation-js-splitting
__('You have {0} subscribers' +
'in your mailing list', [subscribers.length])
// ok: frappe-translation-js-splitting
__("Ctrl+Enter to add comment")
// ruleid: frappe-translation-js-splitting
__('You have {0} subscribers \
in your mailing list', [subscribers.length])

View File

@@ -1,61 +0,0 @@
# Examples taken from https://frappeframework.com/docs/user/en/translations
# This file is used for testing the tests.
from frappe import _
full_name = "Jon Doe"
# ok: frappe-translation-python-formatting
_('Welcome {0}, get started with ERPNext in just a few clicks.').format(full_name)
# ruleid: frappe-translation-python-formatting
_('Welcome %s, get started with ERPNext in just a few clicks.' % full_name)
# ruleid: frappe-translation-python-formatting
_('Welcome %(name)s, get started with ERPNext in just a few clicks.' % {'name': full_name})
# ruleid: frappe-translation-python-formatting
_('Welcome {0}, get started with ERPNext in just a few clicks.'.format(full_name))
subscribers = ["Jon", "Doe"]
# ok: frappe-translation-python-formatting
_('You have {0} subscribers in your mailing list.').format(len(subscribers))
# ruleid: frappe-translation-python-splitting
_('You have') + len(subscribers) + _('subscribers in your mailing list.')
# ruleid: frappe-translation-python-splitting
_('You have {0} subscribers \
in your mailing list').format(len(subscribers))
# ok: frappe-translation-python-splitting
_('You have {0} subscribers') \
+ 'in your mailing list'
# ruleid: frappe-translation-trailing-spaces
msg = _(" You have {0} pending invoice ")
# ruleid: frappe-translation-trailing-spaces
msg = _("You have {0} pending invoice ")
# ruleid: frappe-translation-trailing-spaces
msg = _(" You have {0} pending invoice")
# ok: frappe-translation-trailing-spaces
msg = ' ' + _("You have {0} pending invoices") + ' '
# ruleid: frappe-translation-python-formatting
_(f"can not format like this - {subscribers}")
# ruleid: frappe-translation-python-splitting
_(f"what" + f"this is also not cool")
# ruleid: frappe-translation-empty-string
_("")
# ruleid: frappe-translation-empty-string
_('')
class Test:
# ok: frappe-translation-python-splitting
def __init__(
args
):
pass

View File

@@ -1,64 +0,0 @@
rules:
- id: frappe-translation-empty-string
pattern-either:
- pattern: _("")
- pattern: __("")
message: |
Empty string is useless for translation.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [python, javascript, json]
severity: ERROR
- id: frappe-translation-trailing-spaces
pattern-either:
- pattern: _("=~/(^[ \t]+|[ \t]+$)/")
- pattern: __("=~/(^[ \t]+|[ \t]+$)/")
message: |
Trailing or leading whitespace not allowed in translate strings.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [python, javascript, json]
severity: ERROR
- id: frappe-translation-python-formatting
pattern-either:
- pattern: _("..." % ...)
- pattern: _("...".format(...))
- pattern: _(f"...")
message: |
Only positional formatters are allowed and formatting should not be done before translating.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [python]
severity: ERROR
- id: frappe-translation-js-formatting
patterns:
- pattern: __(`...`)
- pattern-not: __("...")
message: |
Template strings are not allowed for text formatting.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [javascript, json]
severity: ERROR
- id: frappe-translation-python-splitting
pattern-either:
- pattern: _(...) + _(...)
- pattern: _("..." + "...")
- pattern-regex: '[\s\.]_\([^\)]*\\\s*' # lines broken by `\`
- pattern-regex: '[\s\.]_\(\s*\n' # line breaks allowed by python for using ( )
message: |
Do not split strings inside translate function. Do not concatenate using translate functions.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [python]
severity: ERROR
- id: frappe-translation-js-splitting
pattern-either:
- pattern-regex: '__\([^\)]*[\\]\s+'
- pattern: __('...' + '...', ...)
- pattern: __('...') + __('...')
message: |
Do not split strings inside translate function. Do not concatenate using translate functions.
Please refer: https://frappeframework.com/docs/user/en/translations
languages: [javascript, json]
severity: ERROR

View File

@@ -1,9 +0,0 @@
// ok: frappe-missing-translate-function-js
frappe.msgprint('{{ _("Both login and password required") }}');
// ruleid: frappe-missing-translate-function-js
frappe.msgprint('What');
// ok: frappe-missing-translate-function-js
frappe.throw(' {{ _("Both login and password required") }}. ');

View File

@@ -1,30 +0,0 @@
rules:
- id: frappe-missing-translate-function-python
pattern-either:
- patterns:
- pattern: frappe.msgprint("...", ...)
- pattern-not: frappe.msgprint(_("..."), ...)
- patterns:
- pattern: frappe.throw("...", ...)
- pattern-not: frappe.throw(_("..."), ...)
message: |
All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations
languages: [python]
severity: ERROR
- id: frappe-missing-translate-function-js
pattern-either:
- patterns:
- pattern: frappe.msgprint("...", ...)
- pattern-not: frappe.msgprint(__("..."), ...)
# ignore microtemplating e.g. msgprint("{{ _("server side translation") }}")
- pattern-not: frappe.msgprint("=~/\{\{.*\_.*\}\}/i", ...)
- patterns:
- pattern: frappe.throw("...", ...)
- pattern-not: frappe.throw(__("..."), ...)
# ignore microtemplating
- pattern-not: frappe.throw("=~/\{\{.*\_.*\}\}/i", ...)
message: |
All user facing text must be wrapped in translate function. Please refer to translation documentation. https://frappeframework.com/docs/user/en/guides/basics/translations
languages: [javascript]
severity: ERROR

View File

@@ -11,4 +11,4 @@ jobs:
- name: curl
run: |
apk add curl bash
curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'

View File

@@ -10,13 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: returntocorp/semgrep-action@v1
env:
SEMGREP_TIMEOUT: 120
with:
config: >-
r/python.lang.correctness
.github/helper/semgrep_rules
- name: Set up Python 3.8
uses: actions/setup-python@v2
@@ -24,4 +17,15 @@ jobs:
python-version: 3.8
- name: Install and Run Pre-commit
uses: pre-commit/action@v2.0.0
uses: pre-commit/action@v2.0.3
- name: Download Semgrep rules
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
- uses: returntocorp/semgrep-action@v1
env:
SEMGREP_TIMEOUT: 120
with:
config: >-
r/python.lang.correctness
./frappe-semgrep-rules/rules

View File

@@ -99,6 +99,8 @@ jobs:
- name: Build Assets
run: cd ~/frappe-bench/ && bench build
env:
CI: Yes
- name: UI Tests
run: cd ~/frappe-bench/ && bench --site test_site run-ui-tests erpnext --headless

58
.mergify.yml Normal file
View File

@@ -0,0 +1,58 @@
pull_request_rules:
- name: Auto-close PRs on stable branch
conditions:
- and:
- and:
- author!=surajshetty3416
- author!=gavindsouza
- author!=rohitwaghchaure
- author!=nabinhait
- or:
- base=version-13
- base=version-12
actions:
close:
comment:
message: |
@{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on an appropriate hotfix branch.
https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist#which-branch
- name: backport to version-13-hotfix
conditions:
- label="backport version-13-hotfix"
actions:
backport:
branches:
- version-13-hotfix
assignees:
- "{{ author }}"
- name: backport to version-13-pre-release
conditions:
- label="backport version-13-pre-release"
actions:
backport:
branches:
- version-13-pre-release
assignees:
- "{{ author }}"
- name: backport to version-12-hotfix
conditions:
- label="backport version-12-hotfix"
actions:
backport:
branches:
- version-12-hotfix
assignees:
- "{{ author }}"
- name: backport to version-12-pre-release
conditions:
- label="backport version-12-pre-release"
actions:
backport:
branches:
- version-12-pre-release
assignees:
- "{{ author }}"

View File

@@ -20,6 +20,9 @@ repos:
rev: 3.9.2
hooks:
- id: flake8
additional_dependencies: [
'flake8-bugbear',
]
args: ['--config', '.github/helper/.flake8_strict']
exclude: ".*setup.py$"

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ import frappe
from erpnext.hooks import regional_overrides
__version__ = '13.12.0'
__version__ = '13.14.0'
def get_default_company(user=None):
'''Get default company for user'''

View File

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

View File

@@ -45,6 +45,49 @@ frappe.treeview_settings["Account"] = {
],
root_label: "Accounts",
get_tree_nodes: 'erpnext.accounts.utils.get_children',
on_get_node: function(nodes, deep=false) {
if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
let accounts = [];
if (deep) {
// in case of `get_all_nodes`
accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []);
} else {
accounts = nodes;
}
const get_balances = frappe.call({
method: 'erpnext.accounts.utils.get_account_balances',
args: {
accounts: accounts,
company: cur_tree.args.company
},
});
get_balances.then(r => {
if (!r.message || r.message.length == 0) return;
for (let account of r.message) {
const node = cur_tree.nodes && cur_tree.nodes[account.value];
if (!node || node.is_root) continue;
// show Dr if positive since balance is calculated as debit - credit else show Cr
const balance = account.balance_in_account_currency || account.balance;
const dr_or_cr = balance > 0 ? "Dr": "Cr";
const format = (value, currency) => format_currency(Math.abs(value), currency);
if (account.balance!==undefined) {
$('<span class="balance-area pull-right">'
+ (account.balance_in_account_currency ?
(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
+ format(account.balance, account.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
}
}
});
},
add_tree_node: 'erpnext.accounts.utils.add_ac',
menu_items:[
{
@@ -122,24 +165,6 @@ frappe.treeview_settings["Account"] = {
}
}, "add");
},
onrender: function(node) {
if (frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
// show Dr if positive since balance is calculated as debit - credit else show Cr
let balance = node.data.balance_in_account_currency || node.data.balance;
let dr_or_cr = balance > 0 ? "Dr": "Cr";
if (node.data && node.data.balance!==undefined) {
$('<span class="balance-area pull-right">'
+ (node.data.balance_in_account_currency ?
(format_currency(Math.abs(node.data.balance_in_account_currency),
node.data.account_currency) + " / ") : "")
+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
+ " " + dr_or_cr
+ '</span>').insertBefore(node.$ul);
}
}
},
toolbar: [
{
label:__("Add Child"),

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,10 +27,12 @@
"payment_accounts_section",
"party_balance",
"paid_from",
"paid_from_account_type",
"paid_from_account_currency",
"paid_from_account_balance",
"column_break_18",
"paid_to",
"paid_to_account_type",
"paid_to_account_currency",
"paid_to_account_balance",
"payment_amounts_section",
@@ -440,7 +442,8 @@
"depends_on": "eval:(doc.paid_from && doc.paid_to)",
"fieldname": "reference_no",
"fieldtype": "Data",
"label": "Cheque/Reference No"
"label": "Cheque/Reference No",
"mandatory_depends_on": "eval:(doc.paid_from_account_type == 'Bank' || doc.paid_to_account_type == 'Bank')"
},
{
"fieldname": "column_break_23",
@@ -452,6 +455,7 @@
"fieldname": "reference_date",
"fieldtype": "Date",
"label": "Cheque/Reference Date",
"mandatory_depends_on": "eval:(doc.paid_from_account_type == 'Bank' || doc.paid_to_account_type == 'Bank')",
"search_index": 1
},
{
@@ -707,15 +711,30 @@
"label": "Received Amount After Tax (Company Currency)",
"options": "Company:company:default_currency",
"read_only": 1
},
{
"fetch_from": "paid_from.account_type",
"fieldname": "paid_from_account_type",
"fieldtype": "Data",
"hidden": 1,
"label": "Paid From Account Type"
},
{
"fetch_from": "paid_to.account_type",
"fieldname": "paid_to_account_type",
"fieldtype": "Data",
"hidden": 1,
"label": "Paid To Account Type"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-07-09 08:58:15.008761",
"modified": "2021-10-22 17:50:24.632806",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{

View File

@@ -389,7 +389,10 @@ class PaymentEntry(AccountsController):
invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding
invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)
for key, allocated_amount in iteritems(invoice_payment_amount_map):
for idx, (key, allocated_amount) in enumerate(iteritems(invoice_payment_amount_map), 1):
if not invoice_paid_amount_map.get(key):
frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1]))
outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get('discounted_amt'))
@@ -404,7 +407,7 @@ class PaymentEntry(AccountsController):
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
else:
if allocated_amount > outstanding:
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
frappe.throw(_('Row #{0}: Cannot allocate more than {1} against payment term {2}').format(idx, outstanding, key[0]))
if allocated_amount and outstanding:
frappe.db.sql("""
@@ -502,12 +505,13 @@ class PaymentEntry(AccountsController):
def validate_received_amount(self):
if self.paid_from_account_currency == self.paid_to_account_currency:
if self.paid_amount != self.received_amount:
frappe.throw(_("Received Amount should be same as Paid Amount"))
if self.paid_amount < self.received_amount:
frappe.throw(_("Received Amount cannot be greater than Paid Amount"))
def set_received_amount(self):
self.base_received_amount = self.base_paid_amount
if self.paid_from_account_currency == self.paid_to_account_currency:
if self.paid_from_account_currency == self.paid_to_account_currency \
and not self.payment_type == 'Internal Transfer':
self.received_amount = self.paid_amount
def set_amounts_after_tax(self):
@@ -709,10 +713,14 @@ class PaymentEntry(AccountsController):
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
for d in self.get("references"):
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
gle = party_gl_dict.copy()
gle.update({
"against_voucher_type": d.reference_doctype,
"against_voucher": d.reference_name
"against_voucher": d.reference_name,
"cost_center": cost_center
})
allocated_amount_in_company_currency = flt(flt(d.allocated_amount) * flt(d.exchange_rate),
@@ -1045,12 +1053,6 @@ def get_outstanding_reference_documents(args):
party_account_currency = get_account_currency(args.get("party_account"))
company_currency = frappe.get_cached_value('Company', args.get("company"), "default_currency")
# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), args.get("company"), party_account_currency, company_currency)
# Get positive outstanding sales /purchase invoices/ Fees
condition = ""
if args.get("voucher_type") and args.get("voucher_no"):
@@ -1097,6 +1099,12 @@ def get_outstanding_reference_documents(args):
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)
# Get negative outstanding sales /purchase invoices
negative_outstanding_invoices = []
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), party_account_currency, company_currency, condition=condition)
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
if not data:
@@ -1129,22 +1137,26 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
'invoice_amount': flt(d.invoice_amount),
'outstanding_amount': flt(d.outstanding_amount),
'payment_amount': payment_term.payment_amount,
'payment_term': payment_term.payment_term,
'allocated_amount': payment_term.outstanding
'payment_term': payment_term.payment_term
}))
outstanding_invoices_after_split = []
if invoice_ref_based_on_payment_terms:
for idx, ref in invoice_ref_based_on_payment_terms.items():
voucher_no = outstanding_invoices[idx]['voucher_no']
voucher_type = outstanding_invoices[idx]['voucher_type']
voucher_no = ref[0]['voucher_no']
voucher_type = ref[0]['voucher_type']
frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format(
frappe.msgprint(_("Spliting {} {} into {} row(s) as per Payment Terms").format(
voucher_type, voucher_no, len(ref)), alert=True)
outstanding_invoices.pop(idx - 1)
outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]
return outstanding_invoices
existing_row = list(filter(lambda x: x.get('voucher_no') == voucher_no, outstanding_invoices))
index = outstanding_invoices.index(existing_row[0])
outstanding_invoices.pop(index)
outstanding_invoices_after_split += outstanding_invoices
return outstanding_invoices_after_split
def get_orders_to_be_billed(posting_date, party_type, party,
company, party_account_currency, company_currency, cost_center=None, filters=None):
@@ -1211,7 +1223,7 @@ def get_orders_to_be_billed(posting_date, party_type, party,
return order_list
def get_negative_outstanding_invoices(party_type, party, party_account,
company, party_account_currency, company_currency, cost_center=None):
party_account_currency, company_currency, cost_center=None, condition=None):
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
supplier_condition = ""
if voucher_type == "Purchase Invoice":
@@ -1233,19 +1245,21 @@ def get_negative_outstanding_invoices(party_type, party, party_account,
`tab{voucher_type}`
where
{party_type} = %s and {party_account} = %s and docstatus = 1 and
company = %s and outstanding_amount < 0
outstanding_amount < 0
{supplier_condition}
{condition}
order by
posting_date, name
""".format(**{
"supplier_condition": supplier_condition,
"condition": condition,
"rounded_total_field": rounded_total_field,
"grand_total_field": grand_total_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type),
"party_account": "debit_to" if party_type == "Customer" else "credit_to",
"cost_center": cost_center
}), (party, party_account, company), as_dict=True)
}), (party, party_account), as_dict=True)
@frappe.whitelist()

View File

@@ -10,6 +10,9 @@ frappe.ui.form.on('Payment Order', {
}
}
});
frm.set_df_property('references', 'cannot_add_rows', true);
frm.set_df_property('references', 'cannot_delete_rows', true);
},
refresh: function(frm) {
if (frm.doc.docstatus == 0) {

View File

@@ -4,9 +4,14 @@
frappe.provide("erpnext.accounts");
erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.extend({
onload: function() {
var me = this;
const default_company = frappe.defaults.get_default('company');
this.frm.set_value('company', default_company);
this.frm.set_query("party_type", function() {
this.frm.set_value('party_type', '');
this.frm.set_value('party', '');
this.frm.set_value('receivable_payable_account', '');
this.frm.set_query("party_type", () => {
return {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
@@ -14,133 +19,149 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
});
this.frm.set_query('receivable_payable_account', function() {
check_mandatory(me.frm);
this.frm.set_query('receivable_payable_account', () => {
return {
filters: {
"company": me.frm.doc.company,
"company": this.frm.doc.company,
"is_group": 0,
"account_type": frappe.boot.party_account_types[me.frm.doc.party_type]
"account_type": frappe.boot.party_account_types[this.frm.doc.party_type]
}
};
});
this.frm.set_query('bank_cash_account', function() {
check_mandatory(me.frm, true);
this.frm.set_query('bank_cash_account', () => {
return {
filters:[
['Account', 'company', '=', me.frm.doc.company],
['Account', 'company', '=', this.frm.doc.company],
['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Bank', 'Cash']]
]
};
});
this.frm.set_value('party_type', '');
this.frm.set_value('party', '');
this.frm.set_value('receivable_payable_account', '');
var check_mandatory = (frm, only_company=false) => {
var title = __("Mandatory");
if (only_company && !frm.doc.company) {
frappe.throw({message: __("Please Select a Company First"), title: title});
} else if (!frm.doc.company || !frm.doc.party_type) {
frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title});
}
};
},
refresh: function() {
this.frm.disable_save();
this.frm.set_df_property('invoices', 'cannot_delete_rows', true);
this.frm.set_df_property('payments', 'cannot_delete_rows', true);
this.frm.set_df_property('allocation', 'cannot_delete_rows', true);
this.frm.set_df_property('invoices', 'cannot_add_rows', true);
this.frm.set_df_property('payments', 'cannot_add_rows', true);
this.frm.set_df_property('allocation', 'cannot_add_rows', true);
if (this.frm.doc.receivable_payable_account) {
this.frm.add_custom_button(__('Get Unreconciled Entries'), () =>
this.frm.trigger("get_unreconciled_entries")
);
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'primary');
}
if (this.frm.doc.invoices.length && this.frm.doc.payments.length) {
this.frm.add_custom_button(__('Allocate'), () =>
this.frm.trigger("allocate")
);
this.frm.change_custom_button_type('Allocate', null, 'primary');
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default');
}
if (this.frm.doc.allocation.length) {
this.frm.add_custom_button(__('Reconcile'), () =>
this.frm.trigger("reconcile")
);
this.frm.change_custom_button_type('Reconcile', null, 'primary');
this.frm.change_custom_button_type('Get Unreconciled Entries', null, 'default');
this.frm.change_custom_button_type('Allocate', null, 'default');
}
},
company: function() {
var me = this;
this.frm.set_value('party', '');
this.frm.set_value('receivable_payable_account', '');
me.frm.clear_table("allocation");
me.frm.clear_table("invoices");
me.frm.clear_table("payments");
me.frm.refresh_fields();
me.frm.trigger('party');
},
party_type: function() {
this.frm.set_value('party', '');
},
party: function() {
var me = this;
if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
this.frm.set_value('receivable_payable_account', '');
this.frm.trigger("clear_child_tables");
if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) {
return frappe.call({
method: "erpnext.accounts.party.get_party_account",
args: {
company: me.frm.doc.company,
party_type: me.frm.doc.party_type,
party: me.frm.doc.party
company: this.frm.doc.company,
party_type: this.frm.doc.party_type,
party: this.frm.doc.party
},
callback: function(r) {
callback: (r) => {
if (!r.exc && r.message) {
me.frm.set_value("receivable_payable_account", r.message);
this.frm.set_value("receivable_payable_account", r.message);
}
me.frm.refresh();
this.frm.refresh();
}
});
}
},
receivable_payable_account: function() {
this.frm.trigger("clear_child_tables");
this.frm.refresh();
},
clear_child_tables: function() {
this.frm.clear_table("invoices");
this.frm.clear_table("payments");
this.frm.clear_table("allocation");
this.frm.refresh_fields();
},
get_unreconciled_entries: function() {
var me = this;
this.frm.clear_table("allocation");
return this.frm.call({
doc: me.frm.doc,
doc: this.frm.doc,
method: 'get_unreconciled_entries',
callback: function(r, rt) {
if (!(me.frm.doc.payments.length || me.frm.doc.invoices.length)) {
frappe.throw({message: __("No invoice and payment records found for this party")});
callback: () => {
if (!(this.frm.doc.payments.length || this.frm.doc.invoices.length)) {
frappe.throw({message: __("No Unreconciled Invoices and Payments found for this party and account")});
} else if (!(this.frm.doc.invoices.length)) {
frappe.throw({message: __("No Outstanding Invoices found for this party")});
} else if (!(this.frm.doc.payments.length)) {
frappe.throw({message: __("No Unreconciled Payments found for this party")});
}
me.frm.refresh();
this.frm.refresh();
}
});
},
allocate: function() {
var me = this;
let payments = me.frm.fields_dict.payments.grid.get_selected_children();
let payments = this.frm.fields_dict.payments.grid.get_selected_children();
if (!(payments.length)) {
payments = me.frm.doc.payments;
payments = this.frm.doc.payments;
}
let invoices = me.frm.fields_dict.invoices.grid.get_selected_children();
let invoices = this.frm.fields_dict.invoices.grid.get_selected_children();
if (!(invoices.length)) {
invoices = me.frm.doc.invoices;
invoices = this.frm.doc.invoices;
}
return me.frm.call({
doc: me.frm.doc,
return this.frm.call({
doc: this.frm.doc,
method: 'allocate_entries',
args: {
payments: payments,
invoices: invoices
},
callback: function() {
me.frm.refresh();
callback: () => {
this.frm.refresh();
}
});
},
reconcile: function() {
var me = this;
var show_dialog = me.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
var show_dialog = this.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
if (show_dialog && show_dialog.length) {
@@ -172,10 +193,10 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
label: __("Difference Account"),
fieldname: 'difference_account',
reqd: 1,
get_query: function() {
get_query: () => {
return {
filters: {
company: me.frm.doc.company,
company: this.frm.doc.company,
is_group: 0
}
}
@@ -189,7 +210,7 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}]
},
],
primary_action: function() {
primary_action: () => {
const args = dialog.get_values()["allocation"];
args.forEach(d => {
@@ -197,7 +218,7 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
"difference_account", d.difference_account);
});
me.reconcile_payment_entries();
this.reconcile_payment_entries();
dialog.hide();
},
primary_action_label: __('Reconcile Entries')
@@ -223,15 +244,12 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
},
reconcile_payment_entries: function() {
var me = this;
return this.frm.call({
doc: me.frm.doc,
doc: this.frm.doc,
method: 'reconcile',
callback: function(r, rt) {
me.frm.clear_table("allocation");
me.frm.refresh_fields();
me.frm.refresh();
callback: () => {
this.frm.clear_table("allocation");
this.frm.refresh();
}
});
}

View File

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

View File

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

View File

@@ -180,8 +180,7 @@
"fieldname": "pos_transactions",
"fieldtype": "Table",
"label": "POS Transactions",
"options": "POS Invoice Reference",
"reqd": 1
"options": "POS Invoice Reference"
},
{
"fieldname": "pos_opening_entry",
@@ -229,7 +228,7 @@
"link_fieldname": "pos_closing_entry"
}
],
"modified": "2021-05-05 16:59:49.723261",
"modified": "2021-10-20 16:19:25.340565",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Closing Entry",

View File

@@ -40,6 +40,7 @@ class POSInvoice(SalesInvoice):
self.validate_change_amount()
self.validate_change_account()
self.validate_item_cost_centers()
self.validate_warehouse()
self.validate_serialised_or_batched_item()
self.validate_stock_availablility()
self.validate_return_items_qty()

View File

@@ -114,6 +114,8 @@ class POSInvoiceMergeLog(Document):
def merge_pos_invoice_into(self, invoice, data):
items, payments, taxes = [], [], []
loyalty_amount_sum, loyalty_points_sum = 0, 0
rounding_adjustment, base_rounding_adjustment = 0, 0
rounded_total, base_rounded_total = 0, 0
for doc in data:
map_doc(doc, invoice, table_map={ "doctype": invoice.doctype })
@@ -162,6 +164,11 @@ class POSInvoiceMergeLog(Document):
found = True
if not found:
payments.append(payment)
rounding_adjustment += doc.rounding_adjustment
rounded_total += doc.rounded_total
base_rounding_adjustment += doc.rounding_adjustment
base_rounded_total += doc.rounded_total
if loyalty_points_sum:
invoice.redeem_loyalty_points = 1
@@ -171,6 +178,10 @@ class POSInvoiceMergeLog(Document):
invoice.set('items', items)
invoice.set('payments', payments)
invoice.set('taxes', taxes)
invoice.set('rounding_adjustment',rounding_adjustment)
invoice.set('rounding_adjustment',base_rounding_adjustment)
invoice.set('base_rounded_total',base_rounded_total)
invoice.set('rounded_total',rounded_total)
invoice.additional_discount_percentage = 0
invoice.discount_amount = 0.0
invoice.taxes_and_charges = None
@@ -246,7 +257,10 @@ def get_invoice_customer_map(pos_invoices):
return pos_invoice_customer_map
def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions')) or get_all_unconsolidated_invoices()
invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions'))
if frappe.flags.in_test and not invoices:
invoices = get_all_unconsolidated_invoices()
invoice_by_customer = get_invoice_customer_map(invoices)
if len(invoices) >= 10 and closing_entry:

View File

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

View File

@@ -33,7 +33,9 @@ class TestPOSProfile(unittest.TestCase):
frappe.db.sql("delete from `tabPOS Profile`")
def get_customers_list(pos_profile={}):
def get_customers_list(pos_profile=None):
if pos_profile is None:
pos_profile = {}
cond = "1=1"
customer_groups = []
if pos_profile.get('customer_groups'):

View File

@@ -19,6 +19,7 @@ from erpnext.stock.get_item_details import get_item_details
class TestPricingRule(unittest.TestCase):
def setUp(self):
delete_existing_pricing_rules()
setup_pricing_rule_data()
def tearDown(self):
delete_existing_pricing_rules()
@@ -561,6 +562,8 @@ class TestPricingRule(unittest.TestCase):
for doc in [si, si1]:
doc.delete()
test_dependencies = ["Campaign"]
def make_pricing_rule(**args):
args = frappe._dict(args)
@@ -607,6 +610,13 @@ def make_pricing_rule(**args):
if args.get(applicable_for):
doc.db_set(applicable_for, args.get(applicable_for))
def setup_pricing_rule_data():
if not frappe.db.exists('Campaign', '_Test Campaign'):
frappe.get_doc({
'doctype': 'Campaign',
'campaign_name': '_Test Campaign',
'name': '_Test Campaign'
}).insert()
def delete_existing_pricing_rules():
for doctype in ["Pricing Rule", "Pricing Rule Item Code",

View File

@@ -29,6 +29,9 @@ def get_pricing_rules(args, doc=None):
pricing_rules = []
values = {}
if not frappe.db.exists('Pricing Rule', {'disable': 0, args.transaction_type: 1}):
return
for apply_on in ['Item Code', 'Item Group', 'Brand']:
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
@@ -398,7 +401,9 @@ def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
pricing_rules[0].apply_rule_on_other_items = items
return pricing_rules
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=None):
if items is None:
items = []
sum_qty, sum_amt = [0, 0]
doctype = doc.get('parenttype') or doc.doctype

View File

@@ -69,7 +69,9 @@ class PromotionalScheme(Document):
{'promotional_scheme': self.name}):
frappe.delete_doc('Pricing Rule', rule.name)
def get_pricing_rules(doc, rules = {}):
def get_pricing_rules(doc, rules=None):
if rules is None:
rules = {}
new_doc = []
for child_doc, fields in {'price_discount_slabs': price_discount_fields,
'product_discount_slabs': product_discount_fields}.items():
@@ -78,7 +80,9 @@ def get_pricing_rules(doc, rules = {}):
return new_doc
def _get_pricing_rules(doc, child_doc, discount_fields, rules = {}):
def _get_pricing_rules(doc, child_doc, discount_fields, rules=None):
if rules is None:
rules = {}
new_doc = []
args = get_args_for_pricing_rule(doc)
applicable_for = frappe.scrub(doc.get('applicable_for'))

View File

@@ -590,5 +590,11 @@ frappe.ui.form.on("Purchase Invoice", {
company: function(frm) {
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
if (frm.doc.company) {
frappe.db.get_value('Company', frm.doc.company, 'default_payable_account', (r) => {
frm.set_value('credit_to', r.default_payable_account);
});
}
},
})

View File

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

View File

@@ -15,6 +15,7 @@ from erpnext.accounts.deferred_revenue import validate_service_stop_date
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
check_if_return_invoice_linked_with_payment_entry,
get_total_in_party_account_currency,
is_overdue,
unlink_inter_company_doc,
update_linked_doc,
@@ -1147,6 +1148,7 @@ class PurchaseInvoice(BuyingController):
return
outstanding_amount = flt(self.outstanding_amount, self.precision("outstanding_amount"))
total = get_total_in_party_account_currency(self)
if not status:
if self.docstatus == 2:
@@ -1154,9 +1156,9 @@ class PurchaseInvoice(BuyingController):
elif self.docstatus == 1:
if self.is_internal_transfer():
self.status = 'Internal Transfer'
elif is_overdue(self):
elif is_overdue(self, total):
self.status = "Overdue"
elif 0 < outstanding_amount < flt(self.grand_total, self.precision("grand_total")):
elif 0 < outstanding_amount < total:
self.status = "Partly Paid"
elif outstanding_amount > 0 and getdate(self.due_date) >= getdate():
self.status = "Unpaid"

View File

@@ -10,9 +10,17 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.setup_posting_date_time_check();
this._super(doc);
},
company: function() {
erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
let me = this;
if (this.frm.doc.company) {
frappe.db.get_value('Company', this.frm.doc.company, 'default_receivable_account', (r) => {
me.frm.set_value('debit_to', r.default_receivable_account);
});
}
},
onload: function() {
var me = this;
this._super();
@@ -446,12 +454,15 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
},
currency() {
var me = this;
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)
if (this.frm.doc.timesheets) {
this.frm.doc.timesheets.forEach((d) => {
let row = frappe.get_doc(d.doctype, d.name)
set_timesheet_detail_rate(row.doctype, row.name, me.frm.doc.currency, row.timesheet_detail)
});
frm.trigger("calculate_timesheet_totals");
}
}
});
@@ -999,7 +1010,7 @@ frappe.ui.form.on('Sales Invoice', {
frappe.ui.form.on("Sales Invoice Timesheet", {
timesheets_remove(frm, cdt, cdn) {
timesheets_remove(frm) {
frm.trigger("calculate_timesheet_totals");
}
});

View File

@@ -124,6 +124,13 @@
"total_advance",
"outstanding_amount",
"disable_rounded_total",
"column_break4",
"write_off_amount",
"base_write_off_amount",
"write_off_outstanding_amount_automatically",
"column_break_74",
"write_off_account",
"write_off_cost_center",
"advances_section",
"allocate_advances_automatically",
"get_advances",
@@ -144,13 +151,6 @@
"column_break_90",
"change_amount",
"account_for_change_amount",
"column_break4",
"write_off_amount",
"base_write_off_amount",
"write_off_outstanding_amount_automatically",
"column_break_74",
"write_off_account",
"write_off_cost_center",
"terms_section_break",
"tc_name",
"terms",
@@ -161,14 +161,14 @@
"column_break_84",
"language",
"more_information",
"status",
"inter_company_invoice_reference",
"is_internal_customer",
"represents_company",
"customer_group",
"campaign",
"is_discounted",
"col_break23",
"status",
"is_internal_customer",
"is_discounted",
"source",
"more_info",
"debit_to",
@@ -1990,16 +1990,6 @@
"label": "Additional Discount Account",
"options": "Account"
},
{
"default": "0",
"fieldname": "ignore_default_payment_terms_template",
"fieldtype": "Check",
"hidden": 1,
"label": "Ignore Default Payment Terms Template",
"read_only": 1,
"show_days": 1,
"show_seconds": 1
},
{
"allow_on_submit": 1,
"fieldname": "dispatch_address_name",
@@ -2015,6 +2005,14 @@
"label": "Dispatch Address",
"read_only": 1
},
{
"default": "0",
"fieldname": "ignore_default_payment_terms_template",
"fieldtype": "Check",
"hidden": 1,
"label": "Ignore Default Payment Terms Template",
"read_only": 1
},
{
"fieldname": "total_billing_hours",
"fieldtype": "Float",
@@ -2033,7 +2031,7 @@
"link_fieldname": "consolidated_invoice"
}
],
"modified": "2021-09-28 13:09:34.391799",
"modified": "2021-10-11 20:19:38.667508",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@@ -2088,4 +2086,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -1296,12 +1296,20 @@ class SalesInvoice(SellingController):
serial_nos = item.serial_no or ""
si_serial_nos = set(get_serial_nos(serial_nos))
serial_no_diff = si_serial_nos - dn_serial_nos
if si_serial_nos - dn_serial_nos:
frappe.throw(_("Serial Numbers in row {0} does not match with Delivery Note").format(item.idx))
if serial_no_diff:
dn_link = frappe.utils.get_link_to_form("Delivery Note", item.delivery_note)
serial_no_msg = ", ".join(frappe.bold(d) for d in serial_no_diff)
msg = _("Row #{0}: The following Serial Nos are not present in Delivery Note {1}:").format(
item.idx, dn_link)
msg += " " + serial_no_msg
frappe.throw(msg=msg, title=_("Serial Nos Mismatch"))
if item.serial_no and cint(item.qty) != len(si_serial_nos):
frappe.throw(_("Row {0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
frappe.throw(_("Row #{0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
item.idx, item.qty, item.item_code, len(si_serial_nos)))
def update_project(self):
@@ -1470,6 +1478,7 @@ class SalesInvoice(SellingController):
return
outstanding_amount = flt(self.outstanding_amount, self.precision("outstanding_amount"))
total = get_total_in_party_account_currency(self)
if not status:
if self.docstatus == 2:
@@ -1477,9 +1486,9 @@ class SalesInvoice(SellingController):
elif self.docstatus == 1:
if self.is_internal_transfer():
self.status = 'Internal Transfer'
elif is_overdue(self):
elif is_overdue(self, total):
self.status = "Overdue"
elif 0 < outstanding_amount < flt(self.grand_total, self.precision("grand_total")):
elif 0 < outstanding_amount < total:
self.status = "Partly Paid"
elif outstanding_amount > 0 and getdate(self.due_date) >= getdate():
self.status = "Unpaid"
@@ -1506,27 +1515,42 @@ class SalesInvoice(SellingController):
if update:
self.db_set('status', self.status, update_modified = update_modified)
def is_overdue(doc):
outstanding_amount = flt(doc.outstanding_amount, doc.precision("outstanding_amount"))
def get_total_in_party_account_currency(doc):
total_fieldname = (
"grand_total"
if doc.disable_rounded_total
else "rounded_total"
)
if doc.party_account_currency != doc.currency:
total_fieldname = "base_" + total_fieldname
return flt(doc.get(total_fieldname), doc.precision(total_fieldname))
def is_overdue(doc, total):
outstanding_amount = flt(doc.outstanding_amount, doc.precision("outstanding_amount"))
if outstanding_amount <= 0:
return
grand_total = flt(doc.grand_total, doc.precision("grand_total"))
nowdate = getdate()
if doc.payment_schedule:
# calculate payable amount till date
payable_amount = sum(
payment.payment_amount
for payment in doc.payment_schedule
if getdate(payment.due_date) < nowdate
)
today = getdate()
if doc.get('is_pos') or not doc.get('payment_schedule'):
return getdate(doc.due_date) < today
if (grand_total - outstanding_amount) < payable_amount:
return True
# calculate payable amount till date
payment_amount_field = (
"base_payment_amount"
if doc.party_account_currency != doc.currency
else "payment_amount"
)
payable_amount = sum(
payment.get(payment_amount_field)
for payment in doc.payment_schedule
if getdate(payment.due_date) < today
)
return (total - outstanding_amount) < payable_amount
elif getdate(doc.due_date) < nowdate:
return True
def get_discounting_status(sales_invoice):
status = None
@@ -2002,22 +2026,23 @@ def update_multi_mode_option(doc, pos_profile):
def append_payment(payment_mode):
payment = doc.append('payments', {})
payment.default = payment_mode.default
payment.mode_of_payment = payment_mode.parent
payment.mode_of_payment = payment_mode.mop
payment.account = payment_mode.default_account
payment.type = payment_mode.type
doc.set('payments', [])
invalid_modes = []
for pos_payment_method in pos_profile.get('payments'):
pos_payment_method = pos_payment_method.as_dict()
mode_of_payments = [d.mode_of_payment for d in pos_profile.get('payments')]
mode_of_payments_info = get_mode_of_payments_info(mode_of_payments, doc.company)
payment_mode = get_mode_of_payment_info(pos_payment_method.mode_of_payment, doc.company)
for row in pos_profile.get('payments'):
payment_mode = mode_of_payments_info.get(row.mode_of_payment)
if not payment_mode:
invalid_modes.append(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment))
invalid_modes.append(get_link_to_form("Mode of Payment", row.mode_of_payment))
continue
payment_mode[0].default = pos_payment_method.default
append_payment(payment_mode[0])
payment_mode.default = row.default
append_payment(payment_mode)
if invalid_modes:
if invalid_modes == 1:
@@ -2033,6 +2058,24 @@ def get_all_mode_of_payments(doc):
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
{'company': doc.company}, as_dict=1)
def get_mode_of_payments_info(mode_of_payments, company):
data = frappe.db.sql(
"""
select
mpa.default_account, mpa.parent as mop, mp.type as type
from
`tabMode of Payment Account` mpa,`tabMode of Payment` mp
where
mpa.parent = mp.name and
mpa.company = %s and
mp.enabled = 1 and
mp.name in (%s)
group by
mp.name
""", (company, mode_of_payments), as_dict=1)
return {row.get('mop'): row for row in data}
def get_mode_of_payment_info(mode_of_payment, company):
return frappe.db.sql("""
select mpa.default_account, mpa.parent, mp.type as type

View File

@@ -1085,8 +1085,6 @@ class TestSalesInvoice(unittest.TestCase):
actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
frappe.db.commit()
self.assertEqual(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate
@@ -1441,15 +1439,22 @@ class TestSalesInvoice(unittest.TestCase):
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
expected_itemised_tax = {
"999800": {
"_Test Item": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 1500.0
"tax_amount": 1000.0
}
},
"_Test Item 2": {
"Service Tax": {
"tax_rate": 10.0,
"tax_amount": 500.0
}
}
}
expected_itemised_taxable_amount = {
"999800": 15000.0
"_Test Item": 10000.0,
"_Test Item 2": 5000.0
}
self.assertEqual(itemised_tax, expected_itemised_tax)
@@ -2334,6 +2339,18 @@ class TestSalesInvoice(unittest.TestCase):
si.reload()
self.assertEqual(si.status, "Paid")
def test_sales_invoice_submission_post_account_freezing_date(self):
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', add_days(getdate(), 1))
si = create_sales_invoice(do_not_save=True)
si.posting_date = add_days(getdate(), 1)
si.save()
self.assertRaises(frappe.ValidationError, si.submit)
si.posting_date = getdate()
si.submit()
frappe.db.set_value('Accounts Settings', None, 'acc_frozen_upto', None)
def get_sales_invoice_for_e_invoice():
si = make_sales_invoice_for_ewaybill()
si.naming_series = 'INV-2020-.#####'

View File

@@ -16,9 +16,9 @@
"column_break_9",
"billing_amount",
"section_break_11",
"timesheet_detail",
"column_break_5",
"time_sheet",
"timesheet_detail",
"column_break_13",
"project_name"
],
"fields": [
@@ -91,7 +91,6 @@
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"label": "Totals"
@@ -110,11 +109,15 @@
"fieldtype": "Data",
"label": "Project Name",
"read_only": 1
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
}
],
"istable": 1,
"links": [],
"modified": "2021-08-15 18:37:08.084930",
"modified": "2021-10-02 03:48:44.979777",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Timesheet",

View File

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

View File

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

View File

@@ -49,15 +49,24 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
pan_no = ''
parties = []
party_type, party = get_party_details(inv)
has_pan_field = frappe.get_meta(party_type).has_field("pan")
if not tax_withholding_category:
tax_withholding_category, pan_no = frappe.db.get_value(party_type, party, ['tax_withholding_category', 'pan'])
if has_pan_field:
fields = ['tax_withholding_category', 'pan']
else:
fields = ['tax_withholding_category']
tax_withholding_details = frappe.db.get_value(party_type, party, fields, as_dict=1)
tax_withholding_category = tax_withholding_details.get('tax_withholding_category')
pan_no = tax_withholding_details.get('pan')
if not tax_withholding_category:
return
# if tax_withholding_category passed as an argument but not pan_no
if not pan_no:
if not pan_no and has_pan_field:
pan_no = frappe.db.get_value(party_type, party, 'pan')
# Get others suppliers with the same PAN No
@@ -165,6 +174,7 @@ def get_lower_deduction_certificate(tax_details, pan_no):
ldc_name = frappe.db.get_value('Lower Deduction Certificate',
{
'pan_no': pan_no,
'tax_withholding_category': tax_details.tax_withholding_category,
'valid_from': ('>=', tax_details.from_date),
'valid_upto': ('<=', tax_details.to_date)
}, 'name')
@@ -203,6 +213,9 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
# then chargeable value is "prev invoices + advances" value which cross the threshold
tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers)
if cint(tax_details.round_off_tax_amount):
tax_amount = round(tax_amount)
return tax_amount, tax_deducted
def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'):
@@ -322,9 +335,6 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
else:
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
if cint(tax_details.round_off_tax_amount):
tds_amount = round(tds_amount)
return tds_amount
def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers):

View File

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

View File

@@ -68,7 +68,7 @@
{%- if einvoice.ShipDtls -%}
{%- set shipping = einvoice.ShipDtls -%}
<h5 style="margin-bottom: 5px;">Shipping</h5>
<h5 style="margin-bottom: 5px;">Shipped From</h5>
<p>{{ shipping.Gstin }}</p>
<p>{{ shipping.LglNm }}</p>
<p>{{ shipping.Addr1 }}</p>
@@ -86,6 +86,17 @@
{%- if buyer.Addr2 -%} <p>{{ buyer.Addr2 }}</p> {% endif %}
<p>{{ buyer.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.customer_address, "gst_state") }} - {{ buyer.Pin }}</p>
{%- if einvoice.DispDtls -%}
{%- set dispatch = einvoice.DispDtls -%}
<h5 style="margin-bottom: 5px;">Dispatched From</h5>
{%- if dispatch.Gstin -%} <p>{{ dispatch.Gstin }}</p> {% endif %}
<p>{{ dispatch.LglNm }}</p>
<p>{{ dispatch.Addr1 }}</p>
{%- if dispatch.Addr2 -%} <p>{{ dispatch.Addr2 }}</p> {% endif %}
<p>{{ dispatch.Loc }}</p>
<p>{{ frappe.db.get_value("Address", doc.dispatch_address_name, "gst_state") }} - {{ dispatch.Pin }}</p>
{% endif %}
</div>
</div>
<div style="overflow-x: auto;">

View File

@@ -139,9 +139,9 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data["total"] = total
return data
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters={}):
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters=None):
cond = ""
filters = frappe._dict(filters)
filters = frappe._dict(filters or {})
if filters.include_default_book_entries:
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')

View File

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

View File

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

View File

@@ -155,6 +155,8 @@ def get_gl_entries(filters, accounting_dimensions):
if filters.get("group_by") == "Group by Voucher":
order_by_statement = "order by posting_date, voucher_type, voucher_no"
if filters.get("group_by") == "Group by Account":
order_by_statement = "order by account, posting_date, creation"
if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Company",
@@ -421,8 +423,6 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
update_value_in_dict(totals, 'closing', gle)
elif gle.posting_date <= to_date:
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle)
update_value_in_dict(totals, 'total', gle)
if filters.get("group_by") != 'Group by Voucher (Consolidated)':
gle_map[gle.get(group_by)].entries.append(gle)
elif filters.get("group_by") == 'Group by Voucher (Consolidated)':
@@ -436,10 +436,11 @@ def get_accountwise_gle(filters, accounting_dimensions, gl_entries, gle_map):
else:
update_value_in_dict(consolidated_gle, key, gle)
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)
update_value_in_dict(totals, 'closing', gle)
for key, value in consolidated_gle.items():
update_value_in_dict(gle_map[value.get(group_by)].totals, 'total', value)
update_value_in_dict(totals, 'total', value)
update_value_in_dict(gle_map[value.get(group_by)].totals, 'closing', value)
update_value_in_dict(totals, 'closing', value)
entries.append(value)
return totals, entries

View File

@@ -44,16 +44,16 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map):
if rate and tds_deducted:
row = {
'pan' if frappe.db.has_column('Supplier', 'pan') else 'tax_id': supplier_map.get(supplier).pan,
'supplier': supplier_map.get(supplier).name
'pan' if frappe.db.has_column('Supplier', 'pan') else 'tax_id': supplier_map.get(supplier, {}).get('pan'),
'supplier': supplier_map.get(supplier, {}).get('name')
}
if filters.naming_series == 'Naming Series':
row.update({'supplier_name': supplier_map.get(supplier).supplier_name})
row.update({'supplier_name': supplier_map.get(supplier, {}).get('supplier_name')})
row.update({
'section_code': tax_withholding_category,
'entity_type': supplier_map.get(supplier).supplier_type,
'entity_type': supplier_map.get(supplier, {}).get('supplier_type'),
'tds_rate': rate,
'total_amount_credited': total_amount_credited,
'tds_deducted': tds_deducted,

View File

@@ -4,11 +4,14 @@
from __future__ import unicode_literals
from json import loads
import frappe
import frappe.defaults
from frappe import _, throw
from frappe.model.meta import get_field_precision
from frappe.utils import cint, cstr, flt, formatdate, get_number_format_info, getdate, now, nowdate
from six import string_types
import erpnext
@@ -447,7 +450,8 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
# new row with references
new_row = journal_entry.append("accounts")
new_row.update(jv_detail.as_dict().copy())
new_row.update((frappe.copy_doc(jv_detail)).as_dict())
new_row.set(d["dr_or_cr"], d["allocated_amount"])
new_row.set('debit' if d['dr_or_cr'] == 'debit_in_account_currency' else 'credit',
@@ -576,10 +580,10 @@ def remove_ref_doc_link_from_pe(ref_type, ref_no):
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe)))
@frappe.whitelist()
def get_company_default(company, fieldname):
value = frappe.get_cached_value('Company', company, fieldname)
def get_company_default(company, fieldname, ignore_validation=False):
value = frappe.get_cached_value('Company', company, fieldname)
if not value:
if not ignore_validation and not value:
throw(_("Please set default {0} in Company {1}")
.format(frappe.get_meta("Company").get_label(fieldname), company))
@@ -787,16 +791,28 @@ def get_children(doctype, parent, company, is_root=False):
if doctype == 'Account':
sort_accounts(acc, is_root, key="value")
company_currency = frappe.get_cached_value('Company', company, "default_currency")
for each in acc:
each["company_currency"] = company_currency
each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company))
if each.account_currency != company_currency:
each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company))
return acc
@frappe.whitelist()
def get_account_balances(accounts, company):
if isinstance(accounts, string_types):
accounts = loads(accounts)
if not accounts:
return []
company_currency = frappe.get_cached_value("Company", company, "default_currency")
for account in accounts:
account["company_currency"] = company_currency
account["balance"] = flt(get_balance_on(account["value"], in_account_currency=False, company=company))
if account["account_currency"] and account["account_currency"] != company_currency:
account["balance_in_account_currency"] = flt(get_balance_on(account["value"], company=company))
return accounts
def create_payment_gateway_account(gateway, payment_channel="Email"):
from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account

View File

@@ -454,6 +454,17 @@
"onboard": 0,
"type": "Link"
},
{
"dependencies": "GL Entry",
"hidden": 0,
"is_query_report": 1,
"label": "KSA VAT Report",
"link_to": "KSA VAT",
"link_type": "Report",
"onboard": 0,
"only_for": "Saudi Arabia",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -1034,6 +1045,16 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "KSA VAT Setting",
"link_to": "KSA VAT Setting",
"link_type": "DocType",
"onboard": 0,
"only_for": "Saudi Arabia",
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -1082,7 +1103,7 @@
"type": "Link"
}
],
"modified": "2021-08-23 16:06:34.167267",
"modified": "2021-08-26 13:15:52.872470",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounting",

View File

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

View File

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

View File

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

View File

@@ -16,9 +16,8 @@ frappe.query_reports["Fixed Asset Register"] = {
fieldname:"status",
label: __("Status"),
fieldtype: "Select",
options: "In Location\nDisposed",
default: 'In Location',
reqd: 1
options: "\nIn Location\nDisposed",
default: 'In Location'
},
{
"fieldname":"filter_based_on",

View File

@@ -45,12 +45,13 @@ def get_conditions(filters):
if filters.get('cost_center'):
conditions["cost_center"] = filters.get('cost_center')
# In Store assets are those that are not sold or scrapped
operand = 'not in'
if status not in 'In Location':
operand = 'in'
if status:
# In Store assets are those that are not sold or scrapped
operand = 'not in'
if status not in 'In Location':
operand = 'in'
conditions['status'] = (operand, ['Sold', 'Scrapped'])
conditions['status'] = (operand, ['Sold', 'Scrapped'])
return conditions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,29 @@
# Version 13.13.0 Release Notes
### Features & Enhancements
- HR Module onboarding ([#25741](https://github.com/frappe/erpnext/pull/25741))
- Tracking multiple rounds for the interview ([#25482](https://github.com/frappe/erpnext/pull/25482))
- HSN based tax breakup table check in GST Settings (India Localization) ([#27907](https://github.com/frappe/erpnext/pull/27907))
### Fixes
- To improve stock transactions added indexes in stock queries and speed up bin updation ([#27758](https://github.com/frappe/erpnext/pull/27758))
- Interstate internal transfer invoices not visible in GSTR-1 ([#27970](https://github.com/frappe/erpnext/pull/27970))
- Account number and name incorrectly imported using COA importer ([#27967](https://github.com/frappe/erpnext/pull/27967))
- Multiple fixes to timesheets ([#27775](https://github.com/frappe/erpnext/pull/27742))
- Totals row incorrect value in GL Entry ([#27867](https://github.com/frappe/erpnext/pull/27867))
- Sales Order delivery Date not getting set via data import ([#27862](https://github.com/frappe/erpnext/pull/27862))
- Add cost center in gl entry for advance payment entry ([#27840](https://github.com/frappe/erpnext/pull/27840))
- Item Variant selection empty popup on website ([#27924](https://github.com/frappe/erpnext/pull/27924))
- Improve performance of fetching account balance in chart of accounts ([#27661](https://github.com/frappe/erpnext/pull/27661))
- Chart Of Accounts import button not visible ([#27748](https://github.com/frappe/erpnext/pull/27748))
- Website Items with same Item name unhandled, thumbnails missing ([#27720](https://github.com/frappe/erpnext/pull/27720))
- Delete linked Transaction Deletion Record docs on deleting company ([#27785](https://github.com/frappe/erpnext/pull/27785))
- Display appropriate message for Payment Term discrepancies in Payment Entry ([#27749](https://github.com/frappe/erpnext/pull/27749))
- Updated buying onboarding tours. ([#27800](https://github.com/frappe/erpnext/pull/27800))
- Fixed variant qty in BOM while making work order ([#27686](https://github.com/frappe/erpnext/pull/27686))
- Availability slots display, disabled Practitioner Schedule ([#27812](https://github.com/frappe/erpnext/pull/27812))
- Consolidated report not consider company currency ([#27863](https://github.com/frappe/erpnext/pull/27863))
- Batch Number not copied from Purchase Receipt to Stock Entry ([#27794](https://github.com/frappe/erpnext/pull/27794))
- Employee Leave Balance report should only consider ledgers of transaction type Leave Allocation ([#27728](https://github.com/frappe/erpnext/pull/27728))

View File

@@ -0,0 +1,42 @@
# Version 13.14.0 Release Notes
### Features & Enhancements
- KSA E-Invoicing and VAT Report ([#27369](https://github.com/frappe/erpnext/pull/27369))
- Added KSA VAT settings to setup KSA VAT accounts
- New report KSA VAT to check the vat amounts
- Print format for KSA VAT Invoice ([#28166](https://github.com/frappe/erpnext/pull/28166))
- Provision to setup tax for recurring additional salary in Salary Slip ([#27459](https://github.com/frappe/erpnext/pull/27459))
- Add dispatch address in E-invoicing for India localization ([#28084](https://github.com/frappe/erpnext/pull/28084))
- Employee initial work history updated when transfer is performed ([#27768](https://github.com/frappe/erpnext/pull/27768))
- Provision to setup quality inspection teamplte in the operation which will be use in the Job Card([#28219](https://github.com/frappe/erpnext/pull/28219))
- Improved sales invoice submission performance ([#27916](https://github.com/frappe/erpnext/pull/27916))
### Fixes
- Splitting outstanding rows as per payment terms ([#27946](https://github.com/frappe/erpnext/pull/27946))
- Make status filter in Fixed Asset Register optional ([#28126](https://github.com/frappe/erpnext/pull/28126))
- Skip empty rows while updating unsaved BOM cost ([#28136](https://github.com/frappe/erpnext/pull/28136))
- TDS round off not working from second transaction ([#27934](https://github.com/frappe/erpnext/pull/27934))
- Update receivable/payable account on company change in the Sales / Purchase Invoice ([#28057](https://github.com/frappe/erpnext/pull/28057))
- Changes in Maintenance Schedule gets overwritten on save ([#27990](https://github.com/frappe/erpnext/pull/27990))
- Fetch thumbnail from Item master instead of regenerating ([#28005](https://github.com/frappe/erpnext/pull/28005))
- Serial Nos not set in the row after scanning in popup ([#28202](https://github.com/frappe/erpnext/pull/28202))
- Taxjar customer_address fix, currency fix ([#28262](https://github.com/frappe/erpnext/pull/28262))
- TaxJar update - added nexus list, making api call only for nexus ([#27497](https://github.com/frappe/erpnext/pull/27497))
- Don't reset rates in Timesheet Detail when Activity Type is cleared ([#28056](https://github.com/frappe/erpnext/pull/28056))
- Show full item name in search widget ([#28283](https://github.com/frappe/erpnext/pull/28283))
- Avoid automatic customer creation on website user login ([#27914](https://github.com/frappe/erpnext/pull/27914))
- POS Closing Entry without linked invoices ([#28042](https://github.com/frappe/erpnext/pull/28042))
- Added patch to fix production plan status ([#27567](https://github.com/frappe/erpnext/pull/27567))
- Interstate internal transfer invoices was not displying in the GSTR-1 report ([#27970](https://github.com/frappe/erpnext/pull/27970))
- Shows opening balance from filtered from date in the stock balance and stock ledger report ([#26877](https://github.com/frappe/erpnext/pull/26877))
- Employee filter in YTD and MTD in salary slip ([#27997](https://github.com/frappe/erpnext/pull/27997))
- Removed warehouse filter on Batch field for Material Receipt ([#28195](https://github.com/frappe/erpnext/pull/28195))
- Account number and name incorrectly imported using COA importer ([#27967](https://github.com/frappe/erpnext/pull/27967))
- Autoemail report not showing dynamic report filters ([#28114](https://github.com/frappe/erpnext/pull/28114))
- Incorrect VAT Amount in UAE VAT 201 report ([#27994](https://github.com/frappe/erpnext/pull/27994))
- Employee Leave Balance report should only consider ledgers of transaction type Leave Allocation([#27728](https://github.com/frappe/erpnext/pull/27728))

View File

@@ -820,6 +820,38 @@ class AccountsController(TransactionBase):
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
unlink_ref_doc_from_payment_entries(self)
if self.doctype == "Sales Order":
self.unlink_ref_doc_from_po()
def unlink_ref_doc_from_po(self):
so_items = []
for item in self.items:
so_items.append(item.name)
linked_po = list(set(frappe.get_all(
'Purchase Order Item',
filters = {
'sales_order': self.name,
'sales_order_item': ['in', so_items],
'docstatus': ['<', 2]
},
pluck='parent'
)))
if linked_po:
frappe.db.set_value(
'Purchase Order Item', {
'sales_order': self.name,
'sales_order_item': ['in', so_items],
'docstatus': ['<', 2]
},{
'sales_order': None,
'sales_order_item': None
}
)
frappe.msgprint(_("Purchase Orders {0} are un-linked").format("\n".join(linked_po)))
def get_tax_map(self):
tax_map = {}
for tax in self.get('taxes'):
@@ -1037,15 +1069,15 @@ class AccountsController(TransactionBase):
if role_allowed_to_over_bill in user_roles and total_overbilled_amt > 0.1:
frappe.msgprint(_("Overbilling of {} ignored because you have {} role.")
.format(total_overbilled_amt, role_allowed_to_over_bill), title=_("Warning"), indicator="orange")
.format(total_overbilled_amt, role_allowed_to_over_bill), indicator="orange", alert=True)
def throw_overbill_exception(self, item, max_allowed_amt):
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow over-billing, please set allowance in Accounts Settings")
.format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
def get_company_default(self, fieldname, ignore_validation=False):
from erpnext.accounts.utils import get_company_default
return get_company_default(self.company, fieldname)
return get_company_default(self.company, fieldname, ignore_validation=ignore_validation)
def get_stock_items(self):
stock_items = []
@@ -1359,8 +1391,8 @@ class AccountsController(TransactionBase):
total = 0
base_total = 0
for d in self.get("payment_schedule"):
total += flt(d.payment_amount)
base_total += flt(d.base_payment_amount)
total += flt(d.payment_amount, d.precision("payment_amount"))
base_total += flt(d.base_payment_amount, d.precision("base_payment_amount"))
base_grand_total = self.get("base_rounded_total") or self.base_grand_total
grand_total = self.get("rounded_total") or self.grand_total
@@ -1376,8 +1408,9 @@ class AccountsController(TransactionBase):
else:
grand_total -= self.get("total_advance")
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
if total != flt(grand_total, self.precision("grand_total")) or \
base_total != flt(base_grand_total, self.precision("base_grand_total")):
if flt(total, self.precision("grand_total")) != flt(grand_total, self.precision("grand_total")) or \
flt(base_total, self.precision("base_grand_total")) != flt(base_grand_total, self.precision("base_grand_total")):
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
def is_rounded_total_disabled(self):
@@ -1691,17 +1724,58 @@ def get_advance_payment_entries(party_type, party, party_account, order_doctype,
def update_invoice_status():
"""Updates status as Overdue for applicable invoices. Runs daily."""
today = getdate()
for doctype in ("Sales Invoice", "Purchase Invoice"):
frappe.db.sql("""
update `tab{}` as dt set dt.status = 'Overdue'
where dt.docstatus = 1
and dt.status != 'Overdue'
and dt.outstanding_amount > 0
and (dt.grand_total - dt.outstanding_amount) <
(select sum(payment_amount) from `tabPayment Schedule` as ps
where ps.parent = dt.name and ps.due_date < %s)
""".format(doctype), getdate())
UPDATE `tab{doctype}` invoice SET invoice.status = 'Overdue'
WHERE invoice.docstatus = 1
AND invoice.status REGEXP '^Unpaid|^Partly Paid'
AND invoice.outstanding_amount > 0
AND (
{or_condition}
(
(
CASE
WHEN invoice.party_account_currency = invoice.currency
THEN (
CASE
WHEN invoice.disable_rounded_total
THEN invoice.grand_total
ELSE invoice.rounded_total
END
)
ELSE (
CASE
WHEN invoice.disable_rounded_total
THEN invoice.base_grand_total
ELSE invoice.base_rounded_total
END
)
END
) - invoice.outstanding_amount
) < (
SELECT SUM(
CASE
WHEN invoice.party_account_currency = invoice.currency
THEN ps.payment_amount
ELSE ps.base_payment_amount
END
)
FROM `tabPayment Schedule` ps
WHERE ps.parent = invoice.name
AND ps.due_date < %(today)s
)
)
""".format(
doctype=doctype,
or_condition=(
"invoice.is_pos AND invoice.due_date < %(today)s OR"
if doctype == "Sales Invoice"
else ""
)
), {"today": today}
)
@frappe.whitelist()
def get_payment_terms(terms_template, posting_date=None, grand_total=None, base_grand_total=None, bill_date=None):

View File

@@ -132,7 +132,8 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select {field} from `tabSupplier`
where docstatus < 2
and ({key} like %(txt)s
or supplier_name like %(txt)s) and disabled=0
or supplier_name like %(txt)s) and disabled=0
and (on_hold = 0 or (on_hold = 1 and CURDATE() > release_date))
{mcond}
order by
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
@@ -210,12 +211,15 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
meta = frappe.get_meta("Item", cached=True)
searchfields = meta.get_search_fields()
if "description" in searchfields:
searchfields.remove("description")
# these are handled separately
ignored_search_fields = ("item_name", "description")
for ignored_field in ignored_search_fields:
if ignored_field in searchfields:
searchfields.remove(ignored_field)
columns = ''
extra_searchfields = [field for field in searchfields
if not field in ["name", "item_group", "description"]]
if not field in ["name", "item_group", "description", "item_name"]]
if extra_searchfields:
columns = ", " + ", ".join(extra_searchfields)
@@ -252,10 +256,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
if frappe.db.count('Item', cache=True) < 50000:
# scan description only if items are less than 50000
description_cond = 'or tabItem.description LIKE %(txt)s'
return frappe.db.sql("""select tabItem.name,
if(length(tabItem.item_name) > 40,
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
tabItem.item_group,
return frappe.db.sql("""select
tabItem.name, tabItem.item_name, tabItem.item_group,
if(length(tabItem.description) > 40, \
concat(substr(tabItem.description, 1, 40), "..."), description) as description
{columns}
@@ -565,7 +567,7 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters)
query_filters.append(['name', query_selector, dimensions])
output = frappe.get_all(doctype, filters=query_filters)
output = frappe.get_list(doctype, filters=query_filters)
result = [d.name for d in output]
return [(d,) for d in set(result)]

View File

@@ -216,11 +216,14 @@ class StatusUpdater(Document):
overflow_percent = ((item[args['target_field']] - item[args['target_ref_field']]) /
item[args['target_ref_field']]) * 100
if overflow_percent - allowance > 0.01 and role not in frappe.get_roles():
if overflow_percent - allowance > 0.01:
item['max_allowed'] = flt(item[args['target_ref_field']] * (100+allowance)/100)
item['reduce_by'] = item[args['target_field']] - item['max_allowed']
self.limits_crossed_error(args, item, qty_or_amount)
if role not in frappe.get_roles():
self.limits_crossed_error(args, item, qty_or_amount)
else:
self.warn_about_bypassing_with_role(item, qty_or_amount, role)
def limits_crossed_error(self, args, item, qty_or_amount):
'''Raise exception for limits crossed'''
@@ -238,6 +241,19 @@ class StatusUpdater(Document):
frappe.bold(item.get('item_code'))
) + '<br><br>' + action_msg, OverAllowanceError, title = _('Limit Crossed'))
def warn_about_bypassing_with_role(self, item, qty_or_amount, role):
action = _("Over Receipt/Delivery") if qty_or_amount == "qty" else _("Overbilling")
msg = (_("{} of {} {} ignored for item {} because you have {} role.")
.format(
action,
_(item["target_ref_field"].title()),
frappe.bold(item["reduce_by"]),
frappe.bold(item.get('item_code')),
role)
)
frappe.msgprint(msg, indicator="orange", alert=True)
def update_qty(self, update_modified=True):
"""Updates qty or amount at row level

View File

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

View File

@@ -260,7 +260,9 @@ class calculate_taxes_and_totals(object):
self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
def calculate_taxes(self):
self.doc.rounding_adjustment = 0
if not self.doc.get('is_consolidated'):
self.doc.rounding_adjustment = 0
# maintain actual tax rate based on idx
actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
for tax in self.doc.get("taxes") if tax.charge_type == "Actual"])
@@ -312,7 +314,9 @@ class calculate_taxes_and_totals(object):
# adjust Discount Amount loss in last tax iteration
if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
and self.doc.discount_amount and self.doc.apply_discount_on == "Grand Total":
and self.doc.discount_amount \
and self.doc.apply_discount_on == "Grand Total" \
and not self.doc.get('is_consolidated'):
self.doc.rounding_adjustment = flt(self.doc.grand_total
- flt(self.doc.discount_amount) - tax.total,
self.doc.precision("rounding_adjustment"))
@@ -405,11 +409,16 @@ class calculate_taxes_and_totals(object):
self.doc.rounding_adjustment = diff
def calculate_totals(self):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
if self.doc.get("taxes") else flt(self.doc.net_total)
if self.doc.get("taxes"):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
else:
self.doc.grand_total = flt(self.doc.net_total)
self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
if self.doc.get("taxes"):
self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
- flt(self.doc.rounding_adjustment), self.doc.precision("total_taxes_and_charges"))
else:
self.doc.total_taxes_and_charges = 0.0
self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
@@ -446,19 +455,20 @@ class calculate_taxes_and_totals(object):
self.doc.total_net_weight += d.total_weight
def set_rounded_total(self):
if self.doc.meta.get_field("rounded_total"):
if self.doc.is_rounded_total_disabled():
self.doc.rounded_total = self.doc.base_rounded_total = 0
return
if not self.doc.get('is_consolidated'):
if self.doc.meta.get_field("rounded_total"):
if self.doc.is_rounded_total_disabled():
self.doc.rounded_total = self.doc.base_rounded_total = 0
return
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
self.doc.currency, self.doc.precision("rounded_total"))
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
self.doc.currency, self.doc.precision("rounded_total"))
#if print_in_rate is set, we would have already calculated rounding adjustment
self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
self.doc.precision("rounding_adjustment"))
#if print_in_rate is set, we would have already calculated rounding adjustment
self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
self.doc.precision("rounding_adjustment"))
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
def _cleanup(self):
if not self.doc.get('is_consolidated'):

View File

@@ -34,6 +34,7 @@ class Opportunity(TransactionBase):
self.validate_item_details()
self.validate_uom_is_integer("uom", "qty")
self.validate_cust_name()
self.map_fields()
if not self.title:
self.title = self.customer_name
@@ -41,6 +42,15 @@ class Opportunity(TransactionBase):
if not self.with_items:
self.items = []
def map_fields(self):
for field in self.meta.fields:
if not self.get(field.fieldname):
try:
value = frappe.db.get_value(self.opportunity_from, self.party_name, field.fieldname)
frappe.db.set(self, field.fieldname, value)
except Exception:
continue
def make_new_lead_if_required(self):
"""Set lead against new opportunity"""
if (not self.get("party_name")) and self.contact_email:
@@ -295,6 +305,8 @@ def make_request_for_quotation(source_name, target_doc=None):
@frappe.whitelist()
def make_customer(source_name, target_doc=None):
def set_missing_values(source, target):
target.opportunity_name = source.name
if source.opportunity_from == "Lead":
target.lead_name = source.party_name

View File

@@ -41,7 +41,6 @@ class TestECommerceSettings(unittest.TestCase):
def test_tax_rule_validation(self):
frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 0")
frappe.db.commit()
cart_settings = self.get_cart_settings()
cart_settings.enabled = 1

View File

@@ -147,7 +147,7 @@ class WebsiteItem(WebsiteGenerator):
def make_thumbnail(self):
"""Make a thumbnail of `website_image`"""
if frappe.flags.in_import:
if frappe.flags.in_import or frappe.flags.in_migrate:
return
import requests.exceptions

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
from frappe import _dict
from frappe.utils import floor
@@ -96,38 +95,32 @@ class ProductFiltersBuilder:
return
attributes = [row.attribute for row in self.doc.filter_attributes]
attribute_docs = [
frappe.get_doc('Item Attribute', attribute) for attribute in attributes
]
valid_attributes = []
if not attributes:
return []
for attr_doc in attribute_docs:
selected_attributes = []
for attr in attr_doc.item_attribute_values:
or_filters = []
filters= [
["Item Variant Attribute", "attribute", "=", attr.parent],
["Item Variant Attribute", "attribute_value", "=", attr.attribute_value]
]
if self.item_group:
or_filters.extend([
["item_group", "=", self.item_group],
["Website Item Group", "item_group", "=", self.item_group]
])
result = frappe.db.sql(
"""
select
distinct attribute, attribute_value
from
`tabItem Variant Attribute`
where
attribute in %(attributes)s
and attribute_value is not null
""",
{"attributes": attributes},
as_dict=1,
)
if frappe.db.get_all("Item", filters, or_filters=or_filters, limit=1):
selected_attributes.append(attr)
attribute_value_map = {}
for d in result:
attribute_value_map.setdefault(d.attribute, []).append(d.attribute_value)
if selected_attributes:
valid_attributes.append(
_dict(
item_attribute_values=selected_attributes,
name=attr_doc.name
)
)
return valid_attributes
out = []
for name, values in attribute_value_map.items():
out.append(frappe._dict(name=name, item_attribute_values=values))
return out
def get_discount_filters(self, discounts):
discount_filters = []
@@ -147,4 +140,4 @@ class ProductFiltersBuilder:
label = f"{discount}% and below"
discount_filters.append([discount, label])
return discount_filters
return discount_filters

View File

@@ -175,9 +175,7 @@ class TestProductDataEngine(unittest.TestCase):
filter_engine = ProductFiltersBuilder()
attribute_filter = filter_engine.get_attribute_filters()[0]
attributes = attribute_filter.item_attribute_values
attribute_values = [d.attribute_value for d in attributes]
attribute_values = attribute_filter.item_attribute_values
self.assertEqual(attribute_filter.name, "Test Size")
self.assertGreater(len(attribute_values), 0)
@@ -349,4 +347,4 @@ def create_variant_web_item():
variant.save()
if not frappe.db.exists("Website Item", {"variant_of": "Test Web Item"}):
make_website_item(variant, save=True)
make_website_item(variant, save=True)

View File

@@ -1,8 +1,5 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
import frappe.defaults
@@ -17,10 +14,19 @@ def show_cart_count():
return False
def set_cart_count(login_manager):
role, parties = check_customer_or_supplier()
if role == 'Supplier': return
# since this is run only on hooks login event
# make sure user is already a customer
# before trying to set cart count
user_is_customer = is_customer()
if not user_is_customer:
return
if show_cart_count():
from erpnext.e_commerce.shopping_cart.cart import set_cart_count
# set_cart_count will try to fetch existing cart quotation
# or create one if non existent (and create a customer too)
# cart count is calculated from this quotation's items
set_cart_count()
def clear_cart_count(login_manager):
@@ -31,13 +37,13 @@ def update_website_context(context):
cart_enabled = is_cart_enabled()
context["shopping_cart_enabled"] = cart_enabled
def check_customer_or_supplier():
if frappe.session.user:
def is_customer():
if frappe.session.user and frappe.session.user != "Guest":
contact_name = frappe.get_value("Contact", {"email_id": frappe.session.user})
if contact_name:
contact = frappe.get_doc('Contact', contact_name)
for link in contact.links:
if link.link_doctype in ('Customer', 'Supplier'):
return link.link_doctype, link.link_name
if link.link_doctype == 'Customer':
return True
return 'Customer', None
return False

View File

@@ -138,7 +138,9 @@ class Student(Document):
enrollment.submit()
return enrollment
def enroll_in_course(self, course_name, program_enrollment, enrollment_date=frappe.utils.datetime.datetime.now()):
def enroll_in_course(self, course_name, program_enrollment, enrollment_date=None):
if enrollment_date is None:
enrollment_date = frappe.utils.datetime.datetime.now()
try:
enrollment = frappe.get_doc({
"doctype": "Course Enrollment",

View File

@@ -68,5 +68,8 @@ def dump_request_data(data, event="create/order"):
@frappe.whitelist()
def resync(method, name, request_data):
frappe.db.set_value("Shopify Log", name, "status", "Queued", update_modified=False)
if not method.startswith("erpnext.erpnext_integrations.connectors.shopify_connection"):
return
frappe.enqueue(method=method, queue='short', timeout=300, is_async=True,
**{"order": json.loads(request_data), "request_id": name})

View File

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

View File

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

View File

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

View File

@@ -6,17 +6,22 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"is_sandbox",
"taxjar_calculate_tax",
"is_sandbox",
"taxjar_create_transactions",
"credentials",
"api_key",
"cb_keys",
"sandbox_api_key",
"configuration",
"company",
"column_break_10",
"tax_account_head",
"configuration_cb",
"shipping_account_head"
"shipping_account_head",
"section_break_12",
"nexus_address",
"nexus"
],
"fields": [
{
@@ -54,6 +59,7 @@
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "is_sandbox",
"fieldtype": "Check",
"label": "Sandbox Mode"
@@ -63,12 +69,9 @@
"fieldtype": "Password",
"label": "Sandbox API Key"
},
{
"fieldname": "configuration_cb",
"fieldtype": "Column Break"
},
{
"default": "0",
"depends_on": "taxjar_calculate_tax",
"fieldname": "taxjar_create_transactions",
"fieldtype": "Check",
"label": "Create TaxJar Transaction"
@@ -82,11 +85,42 @@
{
"fieldname": "cb_keys",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_12",
"fieldtype": "Section Break",
"label": "Nexus List"
},
{
"fieldname": "nexus_address",
"fieldtype": "HTML",
"label": "Nexus Address"
},
{
"fieldname": "nexus",
"fieldtype": "Table",
"label": "Nexus",
"options": "TaxJar Nexus",
"read_only": 1
},
{
"fieldname": "configuration_cb",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_10",
"fieldtype": "Column Break"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
}
],
"issingle": 1,
"links": [],
"modified": "2020-04-30 04:38:03.311089",
"modified": "2021-11-08 18:02:29.232090",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "TaxJar Settings",

View File

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

View File

@@ -4,9 +4,9 @@ import frappe
import taxjar
from frappe import _
from frappe.contacts.doctype.address.address import get_company_address
from frappe.utils import cint
from frappe.utils import cint, flt
from erpnext import get_default_company
from erpnext import get_default_company, get_region
TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head")
SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head")
@@ -21,6 +21,7 @@ SUPPORTED_STATE_CODES = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', '
'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY']
def get_client():
taxjar_settings = frappe.get_single("TaxJar Settings")
@@ -103,7 +104,7 @@ def get_tax_data(doc):
shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD])
line_items = [get_line_item_dict(item) for item in doc.items]
line_items = [get_line_item_dict(item, doc.docstatus) for item in doc.items]
if from_shipping_state not in SUPPORTED_STATE_CODES:
from_shipping_state = get_state_code(from_address, 'Company')
@@ -139,18 +140,28 @@ def get_state_code(address, location):
return state_code
def get_line_item_dict(item):
return dict(
def get_line_item_dict(item, docstatus):
tax_dict = dict(
id = item.get('idx'),
quantity = item.get('qty'),
unit_price = item.get('rate'),
product_tax_code = item.get('product_tax_category')
)
if docstatus == 1:
tax_dict.update({
'sales_tax':item.get('tax_collectable')
})
return tax_dict
def set_sales_tax(doc, method):
if not TAXJAR_CALCULATE_TAX:
return
if get_region(doc.company) != 'United States':
return
if not doc.items:
return
@@ -164,6 +175,9 @@ def set_sales_tax(doc, method):
setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD])
return
# check if delivering within a nexus
check_for_nexus(doc, tax_dict)
tax_data = validate_tax_request(tax_dict)
if tax_data is not None:
if not tax_data.amount_to_collect:
@@ -191,6 +205,17 @@ def set_sales_tax(doc, method):
doc.run_method("calculate_taxes_and_totals")
def check_for_nexus(doc, tax_dict):
if not frappe.db.get_value('TaxJar Nexus', {'region_code': tax_dict["to_state"]}):
for item in doc.get("items"):
item.tax_collectable = flt(0)
item.taxable_amount = flt(0)
for tax in doc.taxes:
if tax.account_head == TAX_ACCOUNT_HEAD:
doc.taxes.remove(tax)
return
def check_sales_tax_exemption(doc):
# if the party is exempt from sales tax, then set all tax account heads to zero
sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \
@@ -241,7 +266,7 @@ def get_shipping_address_details(doc):
if doc.shipping_address_name:
shipping_address = frappe.get_doc("Address", doc.shipping_address_name)
elif doc.customer_address:
shipping_address = frappe.get_doc("Address", doc.customer_address_name)
shipping_address = frappe.get_doc("Address", doc.customer_address)
else:
shipping_address = get_company_address_details(doc)

View File

@@ -62,7 +62,9 @@ class InpatientRecord(Document):
admit_patient(self, service_unit, check_in, expected_discharge)
@frappe.whitelist()
def discharge(self, check_out=now_datetime()):
def discharge(self, check_out=None):
if not check_out:
check_out = now_datetime()
if (getdate(check_out) < getdate(self.admitted_datetime)):
frappe.throw(_('Discharge date cannot be less than Admission date'))
discharge_patient(self, check_out)

View File

@@ -433,11 +433,12 @@ let check_and_set_availability = function(frm) {
slot_html += `<br><span> <b> ${__('Maximum Capacity:')} </b> ${slot_info.service_unit_capacity} </span>`;
}
slot_html += '</div><br><br>';
slot_html += '</div><br>';
slot_html += slot_info.avail_slot.map(slot => {
appointment_count = 0;
disabled = false;
count_class = tool_tip = '';
start_str = slot.from_time;
slot_start_time = moment(slot.from_time, 'HH:mm:ss');
slot_end_time = moment(slot.to_time, 'HH:mm:ss');
@@ -486,10 +487,11 @@ let check_and_set_availability = function(frm) {
data-duration=${interval}
data-service-unit="${slot_info.service_unit || ''}"
style="margin: 0 10px 10px 0; width: auto;" ${disabled ? 'disabled="disabled"' : ""}
data-toggle="tooltip" title="${tool_tip}">
${start_str.substring(0, start_str.length - 3)}<br>
<span class='badge ${count_class}'> ${count} </span>
data-toggle="tooltip" title="${tool_tip || ''}">
${start_str.substring(0, start_str.length - 3)}
${slot_info.service_unit_capacity ? `<br><span class='badge ${count_class}'> ${count} </span>` : ''}
</button>`;
}).join("");
if (slot_info.service_unit_capacity) {

View File

@@ -354,7 +354,7 @@ def get_available_slots(practitioner_doc, date):
validate_practitioner_schedules(schedule_entry, practitioner)
practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule_entry.schedule)
if practitioner_schedule:
if practitioner_schedule and not practitioner_schedule.disabled:
available_slots = []
for time_slot in practitioner_schedule.time_slots:
if weekday == time_slot.day:

View File

@@ -21,6 +21,7 @@ class TestPatientMedicalRecord(unittest.TestCase):
def setUp(self):
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
frappe.db.sql('delete from `tabPatient Appointment`')
make_pos_profile()
def test_medical_record(self):

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import unittest
import frappe
from frappe.utils import flt, getdate, nowdate
from frappe.utils import add_days, flt, getdate, nowdate
from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import (
create_appointment,
@@ -33,10 +33,12 @@ class TestTherapyPlan(unittest.TestCase):
self.assertEqual(plan.status, 'Not Started')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
session.start_date = getdate()
frappe.get_doc(session).submit()
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
session.start_date = add_days(getdate(), 1)
frappe.get_doc(session).submit()
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
@@ -44,6 +46,7 @@ class TestTherapyPlan(unittest.TestCase):
appointment = create_appointment(patient, practitioner, nowdate())
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
session.start_date = add_days(getdate(), 2)
session = frappe.get_doc(session)
session.submit()
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed')

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