Compare commits

...

345 Commits

Author SHA1 Message Date
mergify[bot]
8be179c860 chore: correct license text for GPLv3 (backport #32170) (#32173)
* chore: correct license text for GPLv3 (#32170)

[skip ci]
2022-09-12 14:01:29 +05:30
RJPvT
0b36799e8f fix: Exception handling in Plaid Integration
fix: Exception handling in Plaid Integration
2022-09-12 09:23:23 +05:30
Marica
1ee62a8342 Merge pull request #31280 from RJPvT/patch-2
fix: locale Currency and Float setting in update_employee
2022-06-09 18:29:56 +05:30
RJPvT
74748c03e2 fix: locale Currency and Float setting in update_employee
In fieldtypes locale settings (example NL) . and , changes whereby the field is inproperly filled
2022-06-08 10:55:15 +02:00
mergify[bot]
73484ef1bc fix(india): e-invoice eligibility if company gstin is not configured (#31276) 2022-06-08 12:55:16 +05:30
mergify[bot]
1c25d7c6f2 fix(india): error while parsing e-invoice (backport #31053) (#31224) 2022-06-06 14:28:40 +05:30
mergify[bot]
432210d13d fix(india): minor e-invoicing fixes (backport #30553) (#31067) 2022-05-19 14:26:38 +05:30
mergify[bot]
836bfc603a fix(stock_ledger): round off values near to zero (#30803)
(cherry picked from commit 6a014d12c1)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2022-04-26 10:16:06 +05:30
mergify[bot]
2d7c678a9d fix: warehouse naming when suffix is present (#30621) (#30768)
(cherry picked from commit be04eaf723)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2022-04-21 12:04:25 +05:30
Ankush Menat
a92c53dd2b chore: disable coverage
coverage adds overhead which isn't necessary on v12 branch now

[skip ci]
2022-04-21 11:41:08 +05:30
mergify[bot]
68fd8a1dcf fix(india): transporter name is null while generating e-way bill (backport #30736) 2022-04-20 19:48:22 +05:30
mergify[bot]
5b2b76c4a7 fix: dont fetch entire barcode table in get_item_details (#30131) (#30666)
(cherry picked from commit 64905188c4)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2022-04-10 11:52:35 +05:30
Saqib Ansari
c8780b0062 Merge pull request #30401 from nextchamp-saqib/add-client-cred-fields-einvoicing
feat: add client id & client secret fields in e invoice settings
2022-03-25 10:28:57 +05:30
Saqib Ansari
f531d1a69b feat: add client id & client secret fields in e invoice settings 2022-03-24 17:50:05 +05:30
Rucha Mahabal
51aa55f3b0 fix: salary slip amount rounding errors (#30250) 2022-03-15 12:23:48 +05:30
Saqib Ansari
db0e3d3fbe Merge pull request #30088 from frappe/mergify/bp/version-12-hotfix/pr-30084
fix(e-invoicing): remove batch no from e-invoices (backport #30084)
2022-03-07 11:57:29 +05:30
Saqib Ansari
ccffcf2596 fix(e-invoicing): remove batch no from e-invoices
(cherry picked from commit 031a0dd703)
2022-03-07 06:25:43 +00:00
Saqib Ansari
c74a6f1827 Merge pull request #29291 from GangaManoj/prevent-depr-of-sold-assets
fix: Display 'Make Depreciation Entry' only for submitted or partially depreciated Assets
2022-01-14 18:49:13 +05:30
GangaManoj
73243c8ac3 fix: Hide Make Depreciation Entry if the Asset is not in the Submitted or Partially Depreciated state 2022-01-14 17:40:59 +05:30
GangaManoj
1800ce2780 fix: Only allow posting of Depreciation Entries if the Asset is in the Submitted or Partially Depreciated state 2022-01-14 15:33:16 +05:30
Ankush Menat
e5ea16a6dd fix: loosen dependencies for pandas 2022-01-10 18:12:50 +05:30
rohitwaghchaure
753adf3ce4 Merge pull request #29063 from rohitwaghchaure/fixed-backport-issue
fix: travis failing
2021-12-29 23:27:46 +05:30
Rohit Waghchaure
fbbf29e829 fix: travis failing 2021-12-29 15:46:14 +05:30
Ganga Manoj
ce2aa767b2 fix: Use depreciation cost center for creating credit entries in JEs (#28908) 2021-12-23 12:04:15 +05:30
Ankush Menat
c9927efcae test: dynamic fiscal year creation in tests (#28667)
(cherry picked from commit fdffa037b5)

fix: resolve conflict

fix
2021-12-14 22:50:26 +05:30
Rucha Mahabal
e9dbb46a06 fix: incorrect amount based on payment days in timesheet salary slip (#28884) 2021-12-14 20:04:37 +05:30
mergify[bot]
39125a78e0 fix!: dont allow renaming warehouse primary key (backport #28712)
* fix!: dont allow renaming warehouse primary key

(cherry picked from commit 72dbc3d6b8)

* fix: remove autocommit from item rename

(cherry picked from commit 5caf411be3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-12-14 17:45:08 +05:30
Saqib
2a00164059 Merge pull request #28848 from frappe/mergify/bp/version-12-hotfix/pr-28797
fix: validate if asset account is set against company (backport #28797)
2021-12-13 22:41:15 +05:30
Saqib
7d1953bb3b fix: validate if asset account is set against company
(cherry picked from commit c3e0de28b1)
2021-12-13 14:44:48 +00:00
Deepesh Garg
33eeb64fec Merge pull request #28463 from frappe/mergify/bp/version-12-hotfix/pr-28459
fix(India): GST category not getting auto updated (backport #28459)
2021-12-03 09:39:09 +05:30
mergify[bot]
abb4d99ca8 fix: actual tax conversion in case of multicurrency invoices (#28687) 2021-12-02 15:01:06 +05:30
Deepesh Garg
67f17c7a0c fix: Remove tests 2021-11-29 18:05:36 +05:30
Ankush Menat
24c004b537 fix: use get_all instead of get_list for child tables
(cherry picked from commit f862339024)
2021-11-29 16:28:04 +05:30
Ankush Menat
1fce25180c chore: correct docstrings
(cherry picked from commit c7701ace80)
2021-11-29 16:28:04 +05:30
Saqib
23946cea2e fix: debit & credit currency in bank transaction (#28574) 2021-11-29 15:13:22 +05:30
mergify[bot]
1b78c501a1 fix: incorrect balance for warehouses (#28583) (#28585)
(cherry picked from commit 7ff30a4b2b)

Co-authored-by: Noah Jacob <noahjacobkurian@gmail.com>
2021-11-26 17:36:16 +05:30
Deepesh Garg
d09ed0a578 fix: Conflicts 2021-11-19 13:11:07 +05:30
Deepesh Garg
9b83e3856a fix: Add test for gst category check
(cherry picked from commit cdbc991e3f)

# Conflicts:
#	erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
2021-11-19 06:52:43 +00:00
Deepesh Garg
656686f2b1 fix(India): GST category not getting auto updated
(cherry picked from commit f8a26a9fac)
2021-11-19 06:52:42 +00:00
mergify[bot]
8e7ee953c1 chore: remove woocommerce package (#25736) (#28424)
This is not used anywhere. It was added in this commit
df83148d7c
even there it isn't being used.

(cherry picked from commit e1ab290911)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-11-17 09:50:18 +05:30
mergify[bot]
d2af2b31e5 fix: validate hmac unconditionally (#28375)
(cherry picked from commit c0f06bc8e3)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-12 14:53:51 +05:30
mergify[bot]
f79651c54d fix(WooCommerce): always expect signature in webhook requests (#28371)
(cherry picked from commit 24b048925b)

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-11-12 14:10:49 +05:30
mergify[bot]
80ba0cf978 fix: specify fields to be set in Lead (backport #28288)
* fix: specify fields to be set in Lead (#28288)

(cherry picked from commit da22744e0f)

# Conflicts:
#	erpnext/shopping_cart/cart.py

* fix: merge conflict

Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-11-09 16:05:37 +05:30
Deepesh Garg
30c1a7bb20 Merge pull request #28279 from frappe/mergify/bp/version-12-hotfix/pr-28065
fix(minor): check if gst_category exists while validating GSTIN (backport #28065)
2021-11-09 13:48:29 +05:30
Anuja Pawar
d119b4321d fix: sider
(cherry picked from commit f2fbcc8124)
2021-11-08 18:37:03 +00:00
Anuja Pawar
4b1befb691 fix: update set_value query
(cherry picked from commit dd3cadd46b)
2021-11-08 18:37:01 +00:00
Anuja Pawar
fa5e018330 fix: re-writing sql query with ORM methods
(cherry picked from commit bc1e7bc15f)
2021-11-08 18:36:58 +00:00
Anuja Pawar
8c84d6a1d9 fix: sider
(cherry picked from commit 6a3bd882b4)
2021-11-08 18:36:56 +00:00
Anuja Pawar
f76139dceb fix: sider
(cherry picked from commit 4f53837624)
2021-11-08 18:36:54 +00:00
Anuja Pawar
97544e2bbc fix: check if gst_category exist
(cherry picked from commit 59c31bb124)
2021-11-08 18:36:53 +00:00
mergify[bot]
117718d410 fix: ignore unsupported methods while resyncing (#28210) (#28211)
(cherry picked from commit 72a050fb0b)

Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-11-02 23:09:44 +05:30
Marica
bcb0683be1 Merge pull request #28198 from frappe/mergify/bp/version-12-hotfix/pr-28195
fix: (ux) Remove warehouse filter on Batch field for Material Receipt (backport #28195)
2021-11-02 17:04:23 +05:30
marination
bf5f0a226e chore: Add comment above fix for future reference
(cherry picked from commit 48886ee705)
2021-11-02 10:41:16 +00:00
marination
55aaefb53c fix: Remove warehouse filter on Batch field for Material Receipt
(cherry picked from commit 048210a8f6)
2021-11-02 10:41:15 +00:00
Ankush Menat
ba537b0b93 fix: py2 string formatting 2021-10-29 15:41:55 +05:30
mergify[bot]
89b0e5023a fix: Skip empty rows while updating unsaved BOM cost (#28136) (#28141)
- 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 15:40:14 +05:30
Saqib
14602178e7 Merge pull request #28076 from GangaManoj/gross-profit-backport
feat: Make Gross Profit Report more readable
2021-10-27 15:07:23 +05:30
GangaManoj
5f2819c9b1 fix: Add column names 2021-10-25 02:24:19 +05:30
GangaManoj
5bc7d63646 fix: Get Bundle Items 2021-10-25 02:22:27 +05:30
GangaManoj
94162e0139 fix: Get Bundle Items 2021-10-25 02:15:56 +05:30
GangaManoj
e2e751e26f fix: Remove comments 2021-10-25 02:15:31 +05:30
GangaManoj
70244cee89 fix: Get data when grouped by invoice and otherwise 2021-10-25 02:15:03 +05:30
GangaManoj
ae6e69ebd4 fix: Display only the Invoice rows in bold 2021-10-25 02:14:32 +05:30
GangaManoj
6fdf4dd03e fix: Remove base_rate and buying_rate for Invoice rows 2021-10-25 02:12:21 +05:30
GangaManoj
4aede0ea3f fix: Calculate total buying_amount for each invoice 2021-10-25 02:11:14 +05:30
GangaManoj
de660bf9c4 fix: Fetch bundle item details 2021-10-25 02:11:10 +05:30
GangaManoj
391bf86e0a fix: Fetch base_net_total for each Invoice 2021-10-25 02:10:43 +05:30
GangaManoj
452c613974 fix: Calculate total buying_amount and gross profit for each invoice 2021-10-25 02:08:40 +05:30
GangaManoj
dd7b02ad7d fix: Remove Item Code and Item Name columns 2021-10-25 02:08:39 +05:30
GangaManoj
7cc02bf861 fix: Display Items in the format Item Code: Item Name 2021-10-25 02:08:36 +05:30
GangaManoj
678960209c fix: Add items belonging to Product Bundles as children 2021-10-25 02:08:12 +05:30
GangaManoj
e4995dc9ed fix: Set initial_depth to 3 2021-10-25 02:08:12 +05:30
GangaManoj
7cf5dc7dab fix: Assign indent and parent_invoice 2021-10-25 02:08:08 +05:30
GangaManoj
e676a09c18 fix: Make Invoice row bold 2021-10-25 02:04:03 +05:30
GangaManoj
6431243ce3 fix: Display items as descendants of invoices 2021-10-25 02:04:00 +05:30
GangaManoj
49f93b347c fix: Display data in tree form 2021-10-25 02:02:02 +05:30
mergify[bot]
27e9e47ba8 chore: warning for shopify integration deprecation (backport #26701) (#28062)
* chore: warning for shopify integration deprecation (#26701)

* chore: warning for shopify integration deprecation

* fix: warn deprecation during patch for sysadmins

(cherry picked from commit e43bdf76a5)

# Conflicts:
#	erpnext/patches.txt

* fix: resolve conflicts

Co-authored-by: Ankush <ankush@iwebnotes.com>
Co-authored-by: Ankush Menat <ankush@frappe.io>
2021-10-22 12:16:55 +05:30
Jannat Patel
c9f51d3cec Merge pull request #28017 from frappe/mergify/bp/version-12-hotfix/pr-27728
fix: Employee Leave Balance report should only consider ledgers of transaction type Leave Allocation (backport #27728)
2021-10-20 14:57:52 +05:30
Jannat Patel
9ae3f26dbf fix: conflicts 2021-10-20 12:34:04 +05:30
Goh Yan Chang
ad736f1789 Update employee_leave_balance.py
fix: Employee Leave Balance report showing wrong figures
(cherry picked from commit 632f7848a3)

# Conflicts:
#	erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
2021-10-20 06:58:37 +00:00
Ankush Menat
16ece12516 fix: py2 compatible string formatting 2021-10-09 18:12:07 +05:30
Gavin D'souza
c9e75d2ab5 fix(patch): Handle NULL values from fieldtype change 2021-10-09 18:08:46 +05:30
mergify[bot]
985fdade7e fix(asset): expected value after useful life validation (#27791) 2021-10-05 14:14:52 +05:30
Saqib
10c34da174 fix: unexpected keyword argument 'as_dict' (#27799) 2021-10-05 13:13:20 +05:30
mergify[bot]
d1480be596 fix: set item uom as stock_uom if it isn't set (backport #27623) (#27781)
* fix: set item uom as stock_uom if it isn't set (#27623)

* fix: set item uom as stock_uom if it isn't set

(cherry picked from commit 5c372202d5)

# Conflicts:
#	erpnext/stock/doctype/stock_entry/stock_entry.js

* fix: resolve conflicts

[skip ci]

Co-authored-by: Alan <2.alan.tom@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-10-04 22:50:11 +05:30
Noah Jacob
93a744dc12 fix: empty row on new maintenance visit. (#27626)
* fix: empty row on new maintenance visit.

* fix: check if rows exist
2021-09-30 15:40:37 +05:30
Saqib
a2b98bb80c fix: cannot delete a project if linked with sales order (#27690) 2021-09-28 19:47:08 +05:30
Frappe PR Bot
4fdff12242 fix: set item.qty as mandatory (#27681)
* fix: set item.qty as mandatory in picklist (#27680)

(cherry picked from commit b91333afdd)

# Conflicts:
#	erpnext/stock/doctype/pick_list_item/pick_list_item.json

* fix: resolve conflicts

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-09-28 07:48:37 +00:00
Jannat Patel
9c9cde48ad Merge pull request #27679 from pateljannat/revert-27037-salary-component-account-filter
Revert "fix: salary component account filter"
2021-09-28 11:44:34 +05:30
pateljannat
999a3f1305 Revert 'fix: salary component account filter' 2021-09-28 10:32:33 +05:30
mergify[bot]
8139672c7a fix: Validate if item exists on uploading items in stock reco (#27538) (#27593)
* fix: Validate if item exists on uploading items in stock reco

- Uploading non existent item in stock reco and then changing warehouse or batch gave an error
- Check for non existent item

* chore: translation

Co-authored-by: Marica <maricadsouza221197@gmail.com>
2021-09-20 18:19:14 +05:30
Frappe PR Bot
7169a4c113 fix(plaid): query to check if bank account exists (#27594) 2021-09-20 16:41:26 +05:30
Frappe PR Bot
efddcbe42e fix: no validation on item defaults (#27548)
* fix: no validation on item defaults (#27393)

* fix: no validation on item defaults

* fix: cache value while validating

* test: item default company relation

* fix: reorder validations

* refactor: add guard conditions on update_defaults

* test: add default warehouse for item group

* fix: validate item defaults for item groups

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

# Conflicts:
#	erpnext/stock/doctype/item/item.py

* fix: resolve conflict and remove typehints for py2

Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-09-16 19:55:43 +05:30
Rucha Mahabal
6f6e390863 fix: link to navigate to item template from variant (#27440) 2021-09-11 22:01:22 +05:30
Frappe PR Bot
7843c3d51a fix: set production plan to completed even on over production (#27027) (#27434)
(cherry picked from commit 09f34e558e)

Co-authored-by: Alan <2.alan.tom@gmail.com>
2021-09-11 13:21:46 +05:30
Frappe PR Bot
8871bd4bfb fix: document naming rule not working for subscription invoices (#27394) 2021-09-08 19:11:29 +05:30
Marica
d0a7141e35 Merge pull request #27333 from marination/subcontr-serial-no
fix: Prematurely referenced variable in buying controller for subcontracting
2021-09-03 20:56:02 +05:30
marination
6fe28e83e2 fix: Prematurely referenced variable in buying controller for subcontracting 2021-09-03 20:11:40 +05:30
Frappe PR Bot
abf353a286 Revert "fix: add child item groups into the filters (#26997)" (#27266) (#27267)
This reverts commit c60d5523bc.

(cherry picked from commit 763450dcf8)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-08-31 19:13:25 +05:30
Dany Robert
cef6a8434a fix: remove unwanted serial numbers from fifo_queue (bp #27228)
fifo_queue.remove(serial_no) causes shift in index of the list and thereby not looping through every object in the list.
2021-08-31 10:51:43 +05:30
Frappe PR Bot
dc76094a9f fix: fetch from more than one sales order in Maintenance Visit (#27186)
* fix: fetch from more than one sales order in Maintenance Visit (#26924)

* [fix] #26336

* fix(ux): make customer field reqd for fetching SO

# Conflicts:
#	erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js

* fix: resolve conflicts

Co-authored-by: Pawan Mehta <mehtapawan007@gmail.com>
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>

(cherry picked from commit db69d1dc00)
2021-08-26 23:05:45 +05:30
Frappe PR Bot
1e428f9531 fix: don't allow BOM's item code at any level of child items (#27175)
* fix: don't allow BOM's item code at any level of child items (#27157)

* refactor: bom recursion checking

* fix: dont allow bom recursion

if same item_code is added in child items at any level, it shouldn't be allowed.

* test: add test for bom recursion

* test: fix broken prodplan test using recursive bom

* test: fix recursive bom in tests

(cherry picked from commit c07dce940e)

# Conflicts:
#	erpnext/manufacturing/doctype/bom/test_bom.py
#	erpnext/manufacturing/doctype/production_plan/test_production_plan.py
#	erpnext/manufacturing/doctype/work_order/test_work_order.py

* fix: resolve conflicts

[skip ci]

* fix: conflicts

[skip ci]

* fix: resolve conflicts

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-08-26 19:28:12 +05:30
Raffael Meyer
710c1c1786 feat: add total_billing_hours to Sales Invoice (#26652)
* feat: add `total_billing_hours` to Sales Invoice

* refactor: sider fixes

* style: use double quotes
2021-08-26 12:34:09 +05:30
Nabin Hait
aa358b021e Merge pull request #24844 from dj12djdjs/fix-margin-calculation
fix: multiple price rules margin.
2021-08-24 21:15:28 +05:30
Frappe PR Bot
8bc37da20d fix: calculation of gross profit percentage in Gross Profit Report (#27045) (#27107)
(cherry picked from commit ad06fb2179)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-08-24 20:07:06 +05:30
Frappe PR Bot
914709099f fix: discard empty rows from update items (#27021) (#27094)
(cherry picked from commit 6de7b8ea93)

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-08-24 12:21:18 +05:30
rohitwaghchaure
87dddbe868 Merge branch 'version-12-hotfix' into fix-margin-calculation 2021-08-24 11:08:04 +05:30
Srikant Kedia
ca42b16d3a fix: Price list rate not fetched for return sales invoice fixed (#26593) 2021-08-23 15:38:08 +05:30
Frappe PR Bot
d5e89d98c2 fix: add child item groups into the filters (#26997) (#27034)
* fix: add child item groups into the filters

* fix: appending values to proper variable

* fix: refactor the loop

(cherry picked from commit c60d5523bc)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-08-19 17:09:21 +05:30
Frappe PR Bot
f8fa3860d9 fix: equality check instead of assignment (#27029)
* Merge pull request #27026 from ankush/eq_assign

fix: equality check instead of assignment

[skip ci]

(cherry picked from commit 993b0532f8)

* fix: equality check instead of assignment in cart

port of https://github.com/frappe/erpnext/pull/25372

Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-08-19 15:48:51 +05:30
Türker Tunalı
d8a7abcd02 fix: date_unchanged calculation in "Update Items" (#26992)
Branch corrected https://github.com/frappe/erpnext/pull/26058

  ERPNext generates "Cannot set quantity less than delivered quantity" error even the delivered qty is zero when user clicks "Update Items".
  "date_unchanged" variable gets false value because of new_date is string. 
  
  "getdate(new_date)" corrects the date comparison.
  
  ![ERPNext_PR](https://user-images.githubusercontent.com/710051/121928377-c0263180-cd48-11eb-8cd9-eda7dace09d6.gif)
2021-08-18 17:43:58 +05:30
Ankush Menat
5bb9de8614 ci: backport action on v12 (#27009)
[skip ci]
2021-08-18 17:00:07 +05:30
Ankush Menat
0fd50e0426 fix(deps): pin plaid-python to 7.2.x (#26996)
* fix(deps): pin plaid-python to 7.2.x

Old requirement.txt was allowing next major version which has breaking
changes and causes failure in installation.

* fix(deps): remove frappe from requirements.txt
2021-08-18 08:02:22 +00:00
HENRY Florian
bdfc300896 fix: item name is missing into job card (#26956) 2021-08-17 15:33:26 +05:30
Sagar Vora
14292456cf Merge pull request #26978 from frappe-pr-bot/backport/version-12-hotfix/26976
fix: Incorrect `modified` time in documents that inherit from `StatusUpdater`
2021-08-17 13:21:16 +05:30
Sagar Vora
24d67c35b7 Merge pull request #26976 from resilient-tech/fix-incorrect-modified
fix: Incorrect `modified` time in documents that inherit from `StatusUpdater`
(cherry picked from commit d932cba38a)
2021-08-17 07:48:25 +00:00
Frappe PR Bot
8d71fcb948 fix: fix Payment references from disappearing on adding Cost Center in Payment Entry (#26939)
* fix: payment references from disappearing on selecting cost center (#24831)

Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
(cherry picked from commit 9bf1083d9e)

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

* fix: conflicts

* fix: conflicts

Co-authored-by: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-08-13 17:45:16 +05:30
Frappe PR Bot
2945e604aa fix: remove limit from stock balance report (bp #26773)
(cherry picked from commit b3740e9afc)

Co-authored-by: Ankush <ankush@iwebnotes.com>
2021-08-13 15:44:13 +05:30
Deepesh Garg
ea085b3a76 Merge pull request #26674 from deepeshgarg007/gl_entry_deadlock
fix: Deadlock while doing payment reconciliation
2021-08-12 11:29:34 +05:30
Saqib
611966c139 fix(e-invoicing): cannot cancel invoice if IRN cancelled on portal (#26880) 2021-08-10 17:19:24 +05:30
Raffael Meyer
d650b55f52 Merge branch 'version-12-hotfix' into fix-margin-calculation 2021-08-09 13:21:40 +02:00
Ahmad
8eca908365 perf: speed up validate_account_for_perpetual_inventory (#26730) 2021-08-09 12:17:11 +05:30
Anupam Kumar
09d5ddc42b fix: bank remittance report issue (#26398) (#26767) 2021-08-04 14:03:01 +05:30
Nabin Hait
abd53b114c Merge pull request #25722 from rtdany10/patch-3
feat: Increase number of supported currency exchanges
2021-07-31 11:33:49 +05:30
Ankush
b1e932a6f8 fix: remove incorrect condition in GLE comparison (#26713) 2021-07-29 19:56:36 +05:30
Dany Robert
e6a3e6beb7 Merge branch 'version-12-hotfix' into patch-3 2021-07-29 16:48:12 +05:30
Dany Robert
239974c73e fix issue with cache.setex 2021-07-29 16:00:35 +05:30
Deepesh Garg
27ecb54b8c fix: Deadlock while doing payment reconciliation 2021-07-27 17:49:48 +05:30
Deepesh Garg
6b4b80a4a4 Merge pull request #26629 from deepeshgarg007/exchange_rate_reval_fixes_v12
fix: Exchange rate revaluation posting date and precision fixes
2021-07-27 16:40:11 +05:30
Jannat Patel
68225bbcad Merge pull request #25995 from hasnain2808/fix-issue-priorirty
fix: do not translate issue priority
2021-07-26 10:56:22 +05:30
Deepesh Garg
b549287b94 fix: Convert null values to empty string on grouping 2021-07-25 21:28:40 +05:30
Deepesh Garg
12c3e5dfd6 fix: Remove unintended changes 2021-07-25 21:27:56 +05:30
Deepesh Garg
c908add82e fix: Exchange rate revaluation posting date and precision fixes 2021-07-25 20:03:12 +05:30
Jannat Patel
c74f0f3530 Merge branch 'version-12-hotfix' into fix-issue-priorirty 2021-07-24 18:28:02 +05:30
pateljannat
2e5a358e96 fix: salary component account filter 2021-07-23 13:06:57 +05:30
Subin Tom
01f8833bd1 fix: Fixed clearing issue of payment references on setting cost center (#26548)
Co-authored-by: Subin Tom <subin-home@Subins-MacBook-Air.local>
Co-authored-by: Afshan <33727827+AfshanKhan@users.noreply.github.com>
2021-07-20 21:04:10 +05:30
Nabin Hait
c5a0c22352 Merge branch 'version-12' into version-12-hotfix 2021-07-16 16:10:30 +05:30
Nabin Hait
5e37949411 Merge branch 'v12-pre-release' into version-12 2021-07-16 16:10:30 +05:30
Nabin Hait
fc0459fba9 bumped to version 12.23.0 2021-07-16 16:30:30 +05:50
Nabin Hait
9a1caddacc chore: added change log for v12.23.0 2021-07-16 16:08:40 +05:30
Noah Jacob
b22cbb3122 fix: validation check when no conversion_factor (#26528) 2021-07-16 15:01:14 +05:30
rohitwaghchaure
f4a9e52cbe Merge pull request #26501 from rohitwaghchaure/fixed-taxes-not-working
fix: taxes not set correctly when items pulled from PO to PI
2021-07-16 11:40:56 +05:30
Rohit Waghchaure
24e1786e49 fix: taxes not set correctly when items pulled from PO to PI 2021-07-14 22:52:40 +05:30
Jannat Patel
5399891b25 fix: task status loop (#26007) 2021-07-14 14:43:59 +05:30
Jannat Patel
1b8670b263 fix: Removed company filter for Loan Type (#26463) 2021-07-13 15:29:58 +05:30
Jannat Patel
23db6a8e3a fix: added company filter while fetching loans (#26296)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-07-12 13:17:27 +05:30
Saqib
4c58fb40a8 fix: omit item discount amount for e-invoicing (#26408) 2021-07-12 11:05:37 +05:30
rohitwaghchaure
df045a61ed Merge pull request #26423 from rohitwaghchaure/fixed-serial-no-in-purchase-receipt
fix: serial no issue in subcontract purchase receipt
2021-07-11 10:25:51 +05:30
Rohit Waghchaure
6f7410073f fix: serial no issue in purchase receipt 2021-07-10 22:54:15 +05:30
Saqib
0ecf8f5d66 fix(e-invoicing): allow export invoice even if no taxes applied (#26406) 2021-07-09 15:33:40 +05:30
Jannat Patel
dfc68950c1 fix: lms progress issue (#26254)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-07-02 13:08:38 +05:30
Mohammed Yusuf Shaikh
ee7de6b107 fix: half day to be accounted in its leave type (#26267) 2021-07-02 12:31:59 +05:30
Mohammed Yusuf Shaikh
b2a090f073 fix: Added Permissions for employee to book an appointment (#26246)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-07-02 12:28:43 +05:30
Saqib
704f7b57b8 fix(plaid): cannot reset plaid link for a bank account (#26282) 2021-07-02 11:18:55 +05:30
meike289
8070d76450 feat: add check field for subscription invoice (#25560)
Co-authored-by: Meike Nedwidek <nedwidek@kk-software.de>
2021-06-28 18:35:03 +05:30
Noah Jacob
266563a99a fix: fixed rounding off ordered percent to 100 in condition (#26153) 2021-06-24 21:21:22 +05:30
Saqib
7270b89133 fix: invoices can alter profit and loss of a closed year (#26161) 2021-06-23 19:00:10 +05:30
Jannat Patel
57a68c317e fix: Staffing plan vacancies data type issue (#25940)
* fix: staffing plan vacancies data type issue

* fix: translation issue

* fix: removed greater than 0 condition

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-06-23 14:38:18 +05:30
Jannat Patel
fc44712976 fix: job applicant link issue (#25935)
Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
2021-06-23 12:30:30 +05:30
Saqib
a80d9d81c8 fix(e-invoicing): service item check (#26141) 2021-06-22 14:25:53 +05:30
rohitwaghchaure
6a30025209 Merge pull request #26117 from rohitwaghchaure/fixed-linking-between-mr-and-sq-v12
fix: material request and supplier quotation not linked if supplier quotation created from supplier portal
2021-06-20 19:43:13 +05:30
Rohit Waghchaure
b9fb2349d6 fix: material request and supplier quotation not linked if sq created from supplier portal against rfq 2021-06-20 15:18:35 +05:30
Nabin Hait
2c30ad9465 Merge pull request #26089 from pateljannat/material-request-status-issue-backport
fix: material request status issue
2021-06-18 17:19:41 +05:30
Nabin Hait
67f80216fa Merge branch 'v12-pre-release' into version-12 2021-06-17 19:00:32 +05:30
Nabin Hait
2a8b3841bf Merge branch 'version-12' into version-12-hotfix 2021-06-17 19:00:32 +05:30
Nabin Hait
83b6746cd1 bumped to version 12.22.0 2021-06-17 19:20:32 +05:50
Nabin Hait
94f0aae625 chore: Added change log for v12.22.0 2021-06-17 18:56:13 +05:30
Deepesh Garg
0c4f67b884 Merge pull request #26091 from deepeshgarg007/cash_flow_position
fix: Update positions in default cashflow mappers
2021-06-17 17:17:22 +05:30
Deepesh Garg
fe1d985432 fix: Update positions in default cashflow mappers 2021-06-17 17:15:05 +05:30
pateljannat
57832fc9f8 fix: material request status issue 2021-06-17 10:53:45 +05:30
gavin
56a21343f4 Merge pull request #26001 from frappe/gavindsouza-patch-1
ci: Use only compatible version of bench CLI
2021-06-10 13:33:29 +05:30
gavin
bda432303c ci: Use only compatible version of bench CLI
bench CLI has dropped support for < PY3.6
2021-06-10 13:25:44 +05:30
hasnain2808
371d124a0e fix: do not translate issue priority 2021-06-09 18:40:15 +05:30
Anuja Pawar
3c5b33c241 fix: update cost center in SI (#25972) 2021-06-07 21:15:27 +05:30
Rucha Mahabal
85dca013ee fix: update employee field on renaming employee (#25958) 2021-06-07 15:02:49 +05:30
Saqib
d789dd3897 fix: wrong round off gl entry posted in case of purchase invoice (#25952) 2021-06-06 10:56:01 +05:30
Rucha Mahabal
a1a3f674a2 fix: invalid 'depends_on' expression in opportunity (#25954) 2021-06-04 11:15:55 +05:30
Saqib
7bb95f0a80 feat: cost-center wise period closing entry (#25930) 2021-06-03 17:33:00 +05:30
Ankush Menat
5c450cd13f fix: sync shopify customer addresses (#25937) 2021-06-03 16:48:08 +05:30
Ankush Menat
1c3c2b3006 fix: update shopify api version (#25939) 2021-06-03 16:46:30 +05:30
Deepesh Garg
688a5ac048 Merge pull request #25913 from deepeshgarg007/gst_freight_taxable_value
fix: Backward compatibility for GSTR-1 report
2021-06-02 11:30:57 +05:30
Deepesh Garg
21c15b89ab fix: Add taxable value in Purchase Invoice Item 2021-06-01 21:03:33 +05:30
Deepesh Garg
6a1ccf94a2 fix: Taxable value in GSTR-1 report 2021-06-01 21:02:50 +05:30
Dany Robert
3302ed4658 Merge branch 'version-12-hotfix' into patch-3 2021-05-26 15:51:43 +05:30
Anupam Kumar
fa3ca02557 fix: student invalid password reset link (#25827) 2021-05-26 12:16:25 +05:30
Deepesh Garg
1853f5da80 Merge pull request #25739 from deepeshgarg007/cash_flow_mapper_fix
fix: Cashlfow mapper not showing data
2021-05-24 20:39:59 +05:30
Deepesh Garg
dd82bbf78d Merge branch 'version-12-hotfix' into cash_flow_mapper_fix 2021-05-24 19:56:08 +05:30
Dany Robert
5271ce36de fix: Update test values 2021-05-22 11:22:02 +05:30
Dany Robert
88bab1e3ad fix: update test suite 2021-05-21 23:02:55 +05:30
Dany Robert
6ec804d77f fix: Update hard coded exchange rate values for testing 2021-05-21 18:16:21 +05:30
Nabin Hait
7fa3132a66 Merge branch 'v12-pre-release' into version-12 2021-05-20 18:51:42 +05:30
Nabin Hait
3d3ee778ed Merge branch 'version-12' into version-12-hotfix 2021-05-20 18:51:42 +05:30
Nabin Hait
65b7b57c70 bumped to version 12.21.0 2021-05-20 19:11:42 +05:50
Nabin Hait
4d9c9db295 chore: Added change log for v12.21.0 2021-05-20 18:49:42 +05:30
Deepesh Garg
13927e35cf Merge pull request #25662 from CaseSolvedUK/plaid-24675-v12
fix: plaid NoneType error
2021-05-20 17:03:02 +05:30
Deepesh Garg
18913756eb Merge pull request #25715 from deepeshgarg007/ignore_rouding_diff
fix: Ignore rounding diff while importing JV using data import
2021-05-19 18:26:11 +05:30
Nabin Hait
ccbdf25d44 Merge branch 'version-12-hotfix' into v12-pre-release 2021-05-18 20:30:46 +05:30
Deepesh Garg
ad1f1e000b fix: Cashlfow mapper not showing data 2021-05-18 08:38:49 +05:30
Dany Robert
5cced71ce4 fix: Get the exchange rate based on date. 2021-05-16 12:43:57 +05:30
Dany Robert
aea8773503 feat: Increase number of supported currency exchanges
Switch from frankfurter.app to exchangerate.host to accomodate more currency usage.
Closes #25603
2021-05-15 12:23:05 +05:30
Deepesh Garg
df51aa3087 fix: Ignore rounding diff while importig JV using data import 2021-05-14 21:31:22 +05:30
rohitwaghchaure
2ded94c338 Merge pull request #25693 from rohitwaghchaure/fixed-warehouse-tree-time-out-error
fix: timeout error while loading warehouse tree
2021-05-13 17:21:41 +05:30
Rohit Waghchaure
0b45d5e1ec fix: timeout error while loading warehouse tree 2021-05-13 15:51:39 +05:30
casesolved-co-uk
5946c2f28e fix: plaid NoneType error #24675 2021-05-11 12:36:07 +00:00
rohitwaghchaure
cb2f2d9e73 Merge pull request #25589 from 18alantom/backport-fix-check-schedule-date
fix: check for None in item.schedule_date before setting
2021-05-09 16:57:39 +05:30
Anuja Pawar
39bbc7a245 fix: update item level cost center from POS profile (#25612) 2021-05-08 14:11:06 +05:30
18alantom
062520f1b9 fix: check for None in item.schedule_date before setting 2021-05-05 12:07:18 +05:30
Rucha Mahabal
f644f6feba fix: Employee Separation (#25504)
* fix: Employee Separation

- add ignore_mandatory flag for project creation

- form clean-up

* fix: Employee Separation test
2021-05-03 18:37:13 +05:30
rohitwaghchaure
9de5fe2105 Merge pull request #25552 from rohitwaghchaure/fixed-total-stock-summary-report-12-hotfix
fix: total stock summary report not working
2021-05-03 10:24:34 +05:30
Rohit Waghchaure
e163cb89bf fix: total stock summary report not working 2021-05-02 18:03:29 +05:30
Deepesh Garg
9d38a0eede Merge pull request #25422 from finbyz/patch-2
fix: state code for Other Territory
2021-04-30 11:11:50 +05:30
rohitwaghchaure
c0b66b8203 Merge pull request #25443 from rohitwaghchaure/fixed-incorrect-qty-calculated-for-sub-contracted-raw-materials
fix: incorrect qty calculated for sub-contracted raw materials in purchase receipt
2021-04-27 15:14:03 +05:30
Saqib
96c099c609 fix: remove invalid changes added due to merge conflicts (#25404)
* fix: merge conflicts

* fix: merge conflict

* fix: recover lost method
2021-04-26 15:40:29 +05:30
Jannat Patel
b5be828f3a fix: issue in project custom status (#25453) 2021-04-26 15:36:01 +05:30
Saqib
059b8b567e feat(italy): add document type field for e-invoicing (#25420) 2021-04-26 13:09:04 +05:30
Deepesh Garg
cfdaf7c4aa Merge pull request #25419 from deepeshgarg007/composition_v12_hotfix
fix: Purchase from registered composition dealer
2021-04-24 17:24:18 +05:30
Rohit Waghchaure
5b80679ede fix: incorrect qty calculated for sub-contracted raw materials in purchase receipt 2021-04-22 17:03:02 +05:30
Saqib
a0783de232 fix: remove invalid changes added due to merge conflict (#25405)
* fix: merge conflict

* fix: recover lost method
2021-04-22 14:31:46 +05:30
Saqib
98d90f4e36 fix: remove invalid changes added due to merge conflict (#25437)
* fix: merge conflicts

* fix: recover lost method
2021-04-22 14:14:48 +05:30
Alan
c843da04a4 fix: filter using purpose, make requested changes (#25388)
backported from https://github.com/frappe/erpnext/pull/25352
2021-04-21 21:40:39 +05:30
Alan
34f1d3a88e fix: change subcontracted item display (#25426) 2021-04-21 21:04:28 +05:30
FinByz Tech Pvt. Ltd
bd4461b8cb Update __init__.py
Other Territory state code should be 97.

It's already corrected in version-13 but missed in version-12
2021-04-21 15:46:58 +05:30
Deepesh Garg
06063f7aa6 fix: Test case for GSTR 3b report 2021-04-21 14:14:55 +05:30
Deepesh Garg
472c9e534a fix: Purchase from registered composition dealer 2021-04-21 14:14:45 +05:30
Deepesh Garg
54c9704fe2 Merge pull request #25410 from deepeshgarg007/rcm_rounding_precision
fix: RCM rounding precision
2021-04-20 18:51:24 +05:30
Deepesh Garg
673dcb855d fix: RCM rounding precision 2021-04-20 18:48:50 +05:30
Alan
e3ebe4b33b fix: can't multiply sequence by non-int of type 'float' (#25385)
Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
2021-04-19 15:30:34 +05:30
Saqib
baefc6fd26 fix(e-invoicing): variable scoping (#25368) 2021-04-16 16:22:40 +05:30
Nabin Hait
b95b4e8064 fix: merge conflict 2021-04-16 12:55:46 +05:30
Nabin Hait
08399f9015 bumped to version 12.20.0 2021-04-16 13:11:07 +05:50
Nabin Hait
4481d4e965 chore: added change log 2021-04-16 12:48:27 +05:30
Nabin Hait
3f459c500f Merge branch 'version-12-hotfix' into v12-pre-release 2021-04-16 12:42:36 +05:30
Saqib
e787d05f66 fix(e-invoicing): validations & tax calculation fixes (#25315)
* fix: GST on freight charge in e-invoicing

* fix: cannot fetch e invoice settings

* fix: address validations & cancel eway bill dialog

* fix: except einvoice loading error seperately

* fix: sider

* fix: import format_date

* fix: imports

* fix: test

* fix: test

* fix: test

* fix: validate total condition

* feat: add company link to e-invoice settings

* fix: remove extra condition

* fix: test

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-04-15 18:57:08 +05:30
Deepesh Garg
4eab67347f Merge pull request #25318 from deepeshgarg007/zero_ref_doc_billing_v12
fix: Zero amount completed delivery notes being shown in Sales Invoice get items
2021-04-14 15:28:49 +05:30
Deepesh Garg
cfe20cf610 Merge pull request #25226 from deepeshgarg007/rcm_total_calculation_fix_v12
fix: RCM tax calculation
2021-04-13 20:07:35 +05:30
Ankush Menat
73a7bb88fb fix: remove gst name validation for purch Invoice (#25236)
Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-04-13 19:00:38 +05:30
Ankush Menat
d2d025b586 fix: round total quantity in job card (#25246)
Co-authored-by: Marica <maricadsouza221197@gmail.com>
2021-04-13 18:58:42 +05:30
Ankush Menat
061c82a5cf fix: patch fixes for property setter (#25313)
partial backport of #25220
2021-04-13 18:58:19 +05:30
Ankush Menat
e6eab3b5f8 fix: incorrect status creating PR from PO after creating PI (#25203)
* test: add tests for PO->PI, PO->PR workflow

Add failing test cases for PR status and PR percent billed.

* fix: update PR status in database

* fix: do not copy percent billed from PO to PR

* fix: patch for purchase receipt status

* fix: remove logging in patch for v12 compatibility
2021-04-13 18:57:03 +05:30
Deepesh Garg
16c3a76c49 fix: Applly single transaction threshold on net_total instead of supplier credit amount (#25208) 2021-04-13 18:54:42 +05:30
Shariq Ansari
dd78ffb176 fix: Assignment Rule Unassign Condition doesn't work (#24890) 2021-04-13 18:52:37 +05:30
Shariq Ansari
583a8bf580 fix: Added parent task expected end date validation (#24889) 2021-04-13 18:51:46 +05:30
Jannat Patel
2c63f833b6 fix: serial no refresh issue (#25130)
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
2021-04-13 18:51:05 +05:30
Deepesh Garg
d5d7ef7349 fix: Zero amount completed delivery notes being shown in Sales Invocie get items 2021-04-13 18:45:40 +05:30
Deepesh Garg
ad2d74576b Merge pull request #25165 from KaviyaPeriyasamy/version-12-hotfix-error-log-issue
fix: object referencing same memory address issue
2021-04-13 15:41:15 +05:30
Deepesh Garg
4ced989169 Merge pull request #25204 from ankush/invoice-name-12
fix(India): create property setters for shorter naming series (#25134)
2021-04-13 15:40:14 +05:30
Mohammad Hasnain Mohsin Rajan
a59523970b chore: add sider config (#24892)
Co-authored-by: Sagar Vora <sagar@resilient.tech>
2021-04-13 11:06:01 +05:30
Deepesh Garg
9f2b5ba565 Merge branch 'version-12-hotfix' into rcm_total_calculation_fix_v12 2021-04-12 18:59:30 +05:30
Anupam Kumar
878b10eff5 fix: don't delete mode of payment account details while deleting company transactions (#25218) 2021-04-12 10:37:12 +05:30
Deepesh Garg
83df26197b fix: Rounding adjustment for RCM 2021-04-11 18:45:22 +05:30
Rucha Mahabal
fb87ed3f62 Merge pull request #25216 from anupamvs/hr-compensatory-leave-request-err-msg-v12
fix: error message compensatory leave request
2021-04-08 09:52:24 +05:30
Deepesh Garg
2541ab178a fix: RCM tax calculation 2021-04-06 23:40:46 +05:30
Anupam
ac58e05bbb fix: error message compensatory leave request 2021-04-06 11:40:21 +05:30
Abdullah Abouzekry
34b6f9389c fix: sales order not saving due type mismatch in promo scheme (#24748) (#25056)
Co-authored-by: Ankush Menat <ankush@iwebnotes.com>
2021-04-06 10:14:51 +05:30
Sagar Vora
6678450ba0 fix(India): create property setters for shorter naming series (#25134) 2021-04-05 16:09:41 +05:30
Saqib
fa98c4b8d7 fix(e-invoice): mandatory pincode field not set in e-invoice (#25201) 2021-04-05 14:45:21 +05:30
Saqib
79c7be770c fix(india): critical e-invoicing fixes (#25166)
Co-authored-by: bhavesh95863 <34086262+bhavesh95863@users.noreply.github.com>
2021-04-05 11:01:46 +05:30
rohitwaghchaure
8acc3fbbf4 Merge pull request #25169 from rohitwaghchaure/fixed-incorrect-batch-selected-in-purchase-rceipt
fix: incorrect batch picked in subcontracted purchase receipt
2021-04-03 14:25:10 +05:30
Rohit Waghchaure
2e04026fd6 fix: incorrect batch picked in subcontracted purchase receipt 2021-04-03 14:20:30 +05:30
Kaviya Periyasamy
3707b004c4 fix: object referencing same memory address issue 2021-04-03 12:18:19 +05:30
Saqib
f8dcd06dad fix: santize_for_json is not defined (#25157) 2021-04-02 16:47:50 +05:30
bhavesh95863
15af590482 fix(regional): remove shipping address GSTIN validation for e-invoice (#25133)
Co-authored-by: Saqib <nextchamp.saqib@gmail.com>
2021-04-02 15:05:07 +05:30
Marica
9cc129c400 Merge pull request #25110 from ankush/mr_stopped_validation_v12
fix: do not fetch stopped MR in production plan
2021-04-02 13:16:13 +05:30
Marica
35c4a7a05d Merge branch 'version-12-hotfix' into mr_stopped_validation_v12 2021-04-02 13:15:11 +05:30
Saqib
883598890d fix: place of supply of e-invoicing (#25149) 2021-04-02 12:16:09 +05:30
Afshan
2479e070c4 fix: validation msg for TransDocNo e-invoicing (#25120) 2021-04-01 19:27:41 +05:30
Ankush Menat
8d31d21b88 fix: do not fetch stopped MR in production plan
- Ignore stopped MR while using fetch button
- Add filter on field inside child table.

Related issue: ISS-20-21-10757
2021-03-31 21:21:13 +05:30
Rohan
53a32fecdb fix: commit individual SLE rename for large datasets (#25085) 2021-03-31 15:23:04 +05:30
Sagar Vora
b904304268 fix: revert removed field; not standard in v12 2021-03-29 21:26:53 +05:30
Sagar Vora
bd742d7ad9 fix(Italy): setup, validations, optimisations 2021-03-29 21:21:19 +05:30
Marica
2a1365a278 Merge pull request #24986 from ankush/allow_zero_valuation_SR_v12
fix: Allow zero valuation in stock reconciliation
2021-03-26 12:52:52 +05:30
Deepesh Garg
56531908aa Merge pull request #24974 from deepeshgarg007/tds_check_fix_v12
fix: TDS check getting checked after reload
2021-03-26 12:37:06 +05:30
Marica
f2bede6275 Merge branch 'version-12-hotfix' into allow_zero_valuation_SR_v12 2021-03-25 20:06:51 +05:30
Jannat Patel
a52ea48a21 fix: serial no trim issue (#24950)
* fix: serial no trim issue

* fix: valid serial nos
2021-03-25 15:23:19 +05:30
Anupam Kumar
5bd58ef85c fix: opportunity-quotation mapping order status (#25002) 2021-03-25 11:46:20 +05:30
Devin Slauenwhite
a0cfe449df fix sider errors. 2021-03-23 16:28:54 -04:00
Ankush Menat
19193e8f1c fix: set valuation rate for customer items to zero
- In stock reconciliation always set valuation rate of customer provided
items to zero during validation.
- Let user know the valuation has been changed.
2021-03-23 14:29:12 +05:30
Ankush Menat
ebd230e748 test: customer item in stock reconciliation 2021-03-23 14:26:41 +05:30
Ankush Menat
bf91ee9b99 fix: Allow zero valuation in stock reconciliation
Stock reconciliation can not be done for customer provided item as they
have zero valuation. This change adds a checkbox in item table to allow
such items.

Related issue: ISS-20-21-10248
2021-03-23 14:24:54 +05:30
Deepesh Garg
bb3c44dbb3 fix: TDS check getting checked after reload 2021-03-22 19:42:02 +05:30
Marica
7a61696a25 Merge pull request #24935 from ankush/alt_tags_item_image_v12
feat: allow Item image alt
2021-03-22 11:43:46 +05:30
Marica
28432128be Merge branch 'version-12-hotfix' into alt_tags_item_image_v12 2021-03-22 11:28:50 +05:30
Raffael Meyer
b135569ca6 Merge branch 'version-12-hotfix' into fix-margin-calculation 2021-03-19 16:31:29 +01:00
Saurabh
ce3a680324 Merge branch 'v12-pre-release' into version-12 2021-03-19 19:24:51 +05:30
Saurabh
786d78bce2 bumped to version 12.19.0 2021-03-19 19:44:51 +05:50
rohitwaghchaure
9e3e09f701 Merge pull request #24955 from rohitwaghchaure/revert-stock-balance-value-calculation-pre
fix: revert stock balance value calculation
2021-03-19 16:22:35 +05:30
Rohit Waghchaure
c2e2cf4933 fix: revert stock balance value calculation 2021-03-19 16:07:48 +05:30
rohitwaghchaure
ea50ab8696 Merge pull request #24868 from rohitwaghchaure/revert-stock-balance-value-calculation
fix: revert stock balance value calculation
2021-03-19 16:06:48 +05:30
Deepesh Garg
c22785877d Merge pull request #24952 from nextchamp-saqib/e-invoice-valdiation-fix
fix: NoneType object has no attribute len()
2021-03-19 12:55:30 +05:30
Saqib Ansari
14eeee5592 fix: NoneType object has no attribute len() 2021-03-19 12:51:15 +05:30
Deepesh Garg
4f4f60942c Merge pull request #24919 from deepeshgarg007/nil_exempt_gstr_3b_v12
fix(India): Incorrect Nil Exempt and Non GST amount in GSTR3B report
2021-03-18 21:02:12 +05:30
Shivam Mishra
437c771701 refactor: update confusing label 2021-03-18 12:39:42 +05:30
Shivam Mishra
f29cdb39a1 feat: add alt value in product page 2021-03-18 12:39:00 +05:30
Shivam Mishra
063ab520d3 feat: add image alt argument for product_image macros 2021-03-18 12:38:38 +05:30
Shivam Mishra
b2ae422ed7 feat: add image alt field in items 2021-03-18 12:37:59 +05:30
Deepesh Garg
6da7f65848 fix: Remove print statement 2021-03-17 18:15:24 +05:30
Deepesh Garg
4c6d068a73 fix: Group nil exempted and non gst items separately 2021-03-17 18:15:15 +05:30
Deepesh Garg
ef09599a9f fix(India): Incorrect Nil Exempt and Non GST amount in GSTR3B report 2021-03-17 16:16:33 +05:30
Marica
a1104f040d Merge pull request #24887 from shariquerik/item-attribute-fix-backport
fix: item attributes not editable until refresh
2021-03-16 15:39:36 +05:30
Anurag Mishra
c6a1e3b450 Merge pull request #24228 from YogendrasinhChavda/erpnext_fix_v12
[IMP][version-12] Improved code by adding operator to check condition.
2021-03-16 13:28:31 +05:30
Nabin Hait
238df8b3ec Merge branch 'version-12-hotfix' into v12-pre-release 2021-03-16 11:03:25 +05:30
shariquerik
4db8d13900 fix: item attributes not editable until refresh 2021-03-15 19:10:43 +05:30
Deepesh Garg
6cf37d58f1 fix: Unequal debit and credit issue on RCM Invoice (#24839)
* fix: Unequal debit and credit issue on RCM Invoice

* fix: Travis
2021-03-15 18:04:22 +05:30
Prssanna Desai
386b7fd2c3 fix: use method name as title in error log (#24880) 2021-03-15 18:03:03 +05:30
Ankush
f9f10ed743 fix: Add warning for invalid GST invoice numbers (#24837)
* fix: Add warning for invalid GST invoice numbers

GST Invoice numbers should be 16 characters alphanumeric with dash(/) or
slash(-) only. Add check for doc.name before saving and warn about
naming series.

* refactor: move regex patterns to global variables

Co-authored-by: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com>
2021-03-15 17:58:17 +05:30
Devin Slauenwhite
2e2f3f9578 fix: stock move dialog duplicate submit actions (#24859)
* fix: duplicate submit actions

* fix sider errors.
2021-03-15 17:57:37 +05:30
HENRY Florian
55d45532b4 fix: UOM length unit in global setup list is empty (#24853)
* When ERPNext is installed in localized language the category of UOM Conversion Factor is tranlasted into installed languaes. Filter must be locallized

* fix

* fix
2021-03-15 17:54:50 +05:30
Deepesh Garg
07e7f73488 Merge pull request #24874 from GangaManoj/filter-bank-reconciliation-v12
fix(Bank Reconciliation): Filter Bank Account drop-down list
2021-03-15 10:20:05 +05:30
Ganga Manoj
017d168b03 fix(Bank Reconciliation): Filter Bank Account drop-down list 2021-03-13 23:38:30 +05:30
Rohit Waghchaure
a9d48e5fbf fix: revert stock balance value calculation 2021-03-13 12:48:14 +05:30
Ankush Menat
5ae40871d8 fix: do not update PE title during data import (#24835)
* fix: do not update PE title during data import

Related issue: ISS-20-21-10132

* fix: make title field read only
2021-03-11 16:08:40 +05:30
Ankush Menat
86a163fce5 fix: use account_name only in consolidated report (#24834)
Don't use account_number and only rely on account_name for preparing
consolidated financial statement.

Related issue: ISS-20-21-10217
2021-03-11 16:07:35 +05:30
Devin Slauenwhite
266f24bb74 fix: multiple price rules margin. 2021-03-10 18:46:18 -05:00
Rohan
aa90dc6aa3 fix: do not send emails to disabled users from Employee Onboarding (#24796) 2021-03-09 21:02:57 +05:30
HENRY Florian
5eb8eb8aa7 fix: Add french chart accounts with account number (#24763)
* add new franch account chart with numbers

* add new franch account chart with numbers

* add chart of account with code

* change name chart of accounte

* fix json unicode

* account format

* feat: add french accounting chart with account number

* remove debug
2021-03-09 20:32:30 +05:30
Marica
a69b8aa18d Merge pull request #24790 from ankush/track_settings_v12
fix: track setting changes
2021-03-09 13:30:28 +05:30
Marica
4450a075bd Merge branch 'version-12-hotfix' into track_settings_v12 2021-03-09 11:56:06 +05:30
rohitwaghchaure
3aede7da61 Merge pull request #24709 from rohitwaghchaure/fixed-stock-reco-incorrect-serial-no-issue
fix: incorrect serial no issue in the stock reco
2021-03-07 14:29:02 +05:30
Ankush Menat
2e8b06cf9f fix: track setting changes 2021-03-02 18:20:47 +05:30
Saqib
27f120bc7c fix(india): inflated item tax rate for e-invoicing (#24766)
* fix(india): inflated item tax rate for e-invoicing

* fix: credit note discount on net total
2021-03-01 10:46:17 +05:30
Ankush Menat
5feb20d94b feat: track changes to HR settings (#24740)
related issue: FR-ISS-259927
2021-02-25 19:05:25 +05:30
Afshan
27fbfbf34e fix: reference variable in pricing rule (#24714) 2021-02-25 19:01:58 +05:30
Ankush Menat
d389261230 fix(india): escape for special characters in JSON (bp #24695) (#24705) 2021-02-25 18:04:58 +05:30
Deepesh Garg
e9f8e5814a Merge pull request #24736 from ankush/opening_round_gl12
fix: make round off GLE always non-opening (bp #24723)
2021-02-25 15:17:55 +05:30
Ankush Menat
16193a614e fix: make round off GLE always non-opening
Opening GL entries can not be for profit and loss accounts. Round off
accounts are by default P&L account. Hence when making opening entry,
make round off entries as non-opening.

Related issue: ISS-20-21-09677
2021-02-25 10:22:49 +05:30
Afshan
2b2e205b74 fix: check if customer provided item while setting opening stock (#24633) 2021-02-24 19:05:29 +05:30
Afshan
9272ea838f fix: show custom button for saved projects (#24732)
* fix: show custom button for saved projects

* fix: slider
2021-02-24 18:13:29 +05:30
Afshan
80d9576bb9 fix: currency symbol in update items (#24727) 2021-02-24 16:51:35 +05:30
Afshan
c18a8c58dd fix: column names (#24713) 2021-02-24 14:39:00 +05:30
Rucha Mahabal
473fb55724 Merge pull request #24717 from pateljannat/issue-custom-button-v12
fix: custom buttons in issue
2021-02-24 11:48:06 +05:30
pateljannat
05a3c5a6bc fix: custom buttons in issue 2021-02-23 18:15:50 +05:30
Rohit Waghchaure
c39e206fc7 fix: incorrect serial no issue in the stock reco 2021-02-23 14:26:55 +05:30
Afshan
33539d49f1 fix: error message when making reverse journal entry (#24666) 2021-02-22 19:26:02 +05:30
Deepesh Garg
91a929df84 Merge pull request #24668 from pateljannat/gstr-1-unidentified-accounts-issue-v12
fix: excluding unidentified accounts from gstr-1
2021-02-20 17:28:13 +05:30
Deepesh Garg
e34f73c60b Merge pull request #24670 from deepeshgarg007/transaction_delete_fix_v12
fix: Do not delete GST Accounts from GST Settings on clearing transactions from Company Master
2021-02-19 10:58:13 +05:30
Deepesh Garg
a49ea67f16 fix: Do not delete GST Accounts from GST Settings on clearing transactions from Company Master 2021-02-19 10:56:54 +05:30
pateljannat
4f0c5e2cc7 fix: excluding unidentified accounts from gstr-1 2021-02-18 19:31:11 +05:30
Deepesh Garg
b0e53230bd fix: Prorata factor fixes in subscription (#24637)
* fix: Prorata factor fixes in subscription

* fix: Test Case
2021-02-16 07:49:59 +05:30
Deepesh Garg
1eb3d16667 Merge pull request #24634 from ankush/ladakh_gst_addition-v12hf
fix(India): Add GST state code for Ladakh
2021-02-15 21:12:14 +05:30
Ankush Menat
211a4cb833 fix(India): Add GST state code for Ladakh 2021-02-15 15:30:20 +05:30
rohitwaghchaure
b96c7e0a0f Merge pull request #24618 from rohitwaghchaure/fixed-incorrect-incoming-rate-for-sales-return
fix: incorrect incoming rate for the sales return
2021-02-12 14:20:02 +05:30
Rohit Waghchaure
37604c8d99 fix: incorrect incoming rate for the sales return 2021-02-12 13:17:10 +05:30
Afshan
edfbb5d3be fix: NoneType object has no attribute len() (#24617) 2021-02-12 12:40:52 +05:30
Nabin Hait
81ae1f363c Removed debug flag 2021-02-12 09:53:30 +05:30
Yogendrasinh Chavda
eb88b63ddd [IMP][version-12] Improved code by adding operator to check condition. 2020-12-28 17:40:52 +05:30
185 changed files with 6127 additions and 2428 deletions

32
.flake8 Normal file
View File

@@ -0,0 +1,32 @@
[flake8]
ignore =
E121,
E126,
E127,
E128,
E203,
E225,
E226,
E231,
E241,
E251,
E261,
E265,
E302,
E303,
E305,
E402,
E501,
E741,
W291,
W292,
W293,
W391,
W503,
W504,
F403,
B007,
B950,
W191,
max-line-length = 200

26
.github/workflows/backport.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
jobs:
main:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: "frappe/backport"
path: ./actions
ref: develop
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run backport
uses: ./actions/backport
with:
token: ${{secrets.BACKPORT_BOT_TOKEN}}
labelsToAdd: "backport"
title: "{{originalTitle}}"

View File

@@ -16,11 +16,11 @@ jobs:
include:
- name: "Python 2.7 Server Side Test"
python: 2.7
script: bench --site test_site run-tests --app erpnext --coverage
script: bench --site test_site run-tests --app erpnext
- name: "Python 3.6 Server Side Test"
python: 3.6
script: bench --site test_site run-tests --app erpnext --coverage
script: bench --site test_site run-tests --app erpnext
- name: "Python 2.7 Patch Test"
python: 2.7
@@ -40,8 +40,7 @@ install:
- cd ~
- nvm install 10
- git clone https://github.com/frappe/bench --depth 1
- pip install -e ./bench
- pip install -U frappe-bench --only-binary='all'
- git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
- bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
@@ -75,8 +74,3 @@ install:
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench start &
- bench --site test_site reinstall --yes
after_script:
- pip install coverage==4.5.4
- pip install python-coveralls
- coveralls -b apps/erpnext -d ../../sites/.coverage

View File

@@ -44,6 +44,8 @@ GNU/General Public License (see [license.txt](license.txt))
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Frappe Technologies Pvt Ltd (Frappe) and Contributors.
By contributing to ERPNext, you agree that your contributions will be licensed under its GNU General Public License (v3).
---
## Contributing

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '12.18.0'
__version__ = '12.23.0'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -72,16 +72,14 @@
"138-Autres subventions d'investissement (m\u00eame ventilation que celle du compte 131)": {},
"139-Subventions d'investissement inscrites au compte de r\u00e9sultat": {
"1391-Subventions d'\u00e9quipement": {
"13911-Subventions d'\u00e9quipement": {
"13911-Etat": {},
"13912-R\u00e9gions": {},
"13913-D\u00e9partements": {},
"13914-Communes": {},
"13915-Collectivit\u00e9s publiques": {},
"13916-Entreprises publiques": {},
"13917-Entreprises et organismes priv\u00e9s": {},
"13918-Autres": {}
}
"13911-Etat": {},
"13912-R\u00e9gions": {},
"13913-D\u00e9partements": {},
"13914-Communes": {},
"13915-Collectivit\u00e9s publiques": {},
"13916-Entreprises publiques": {},
"13917-Entreprises et organismes priv\u00e9s": {},
"13918-Autres": {}
},
"1398-Autres subventions d'investissement (m\u00eame ventilation que celle du compte 1391)": {}
}
@@ -536,8 +534,8 @@
"3312-Produits en cours P2": {}
},
"335-Travaux en cours": {
"Travaux en cours T1": {},
"Travaux en cours T2": {}
"3351-Travaux en cours T1": {},
"3352-Travaux en cours T2": {}
}
},
"34-En-cours de production de services": {
@@ -595,7 +593,9 @@
"371-Marchandises (ou groupe) A": {},
"372-Marchandises (ou groupe) B": {}
},
"38-Stocks en voie d'acheminement, mis en d\u00e9p\u00f4t ou donn\u00e9s en consignation (en cas d'inventaire permanent en comptabilit\u00e9 g\u00e9n\u00e9rale)": {},
"38-Stocks en voie d'acheminement, mis en d\u00e9p\u00f4t ou donn\u00e9s en consignation (en cas d'inventaire permanent en comptabilit\u00e9 g\u00e9n\u00e9rale)": {
"account_type": "Stock"
},
"39-D\u00e9pr\u00e9ciations des stocks et en-cours": {
"391-D\u00e9pr\u00e9ciations des mati\u00e8res premi\u00e8res (et fournitures)": {
"3911-Mati\u00e8res (ou groupe) A": {},

View File

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

View File

@@ -21,6 +21,14 @@ frappe.ui.form.on("Bank Reconciliation", {
};
});
frm.set_query("bank_account", function() {
return {
"filters": {
"is_company_account": 1
}
};
});
frm.set_value("from_date", frappe.datetime.month_start());
frm.set_value("to_date", frappe.datetime.month_end());
},

View File

@@ -271,6 +271,7 @@
"label": "Debit",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -304,6 +305,7 @@
"label": "Credit",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -632,6 +634,7 @@
"label": "Allocated Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -731,6 +734,7 @@
"label": "Unallocated Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -755,7 +759,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-05-11 05:27:55.244721",
"modified": "2021-11-26 12:44:55.244721",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Bank Transaction",

View File

@@ -7,19 +7,19 @@ DEFAULT_MAPPERS = [
'section_header': 'Cash flows from operating activities',
'section_leader': 'Adjustments for',
'section_name': 'Operating Activities',
'position': 0,
'position': 1,
'section_subtotal': 'Cash generated from operations',
},
{
'doctype': 'Cash Flow Mapper',
'position': 1,
'position': 2,
'section_footer': 'Net cash used in investing activities',
'section_header': 'Cash flows from investing activities',
'section_name': 'Investing Activities'
},
{
'doctype': 'Cash Flow Mapper',
'position': 2,
'position': 3,
'section_footer': 'Net cash used in financing activites',
'section_header': 'Cash flows from financing activities',
'section_name': 'Financing Activities',

View File

@@ -81,10 +81,11 @@ class ExchangeRateRevaluation(Document):
sum(debit) - sum(credit) as balance
from `tabGL Entry`
where account in (%s)
group by account, party_type, party
and posting_date <= %s
group by account, NULLIF(party_type,''), NULLIF(party,'')
having sum(debit) != sum(credit)
order by account
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
""" % (', '.join(['%s']*len(accounts)), '%s'), tuple(accounts + [self.posting_date]), as_dict=1)
return account_details
@@ -124,9 +125,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate":d.get("new_exchange_rate"),
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
"exchange_rate": flt(d.get("new_exchange_rate"), d.precision("new_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name,
})
@@ -135,9 +136,9 @@ class ExchangeRateRevaluation(Document):
"party_type": d.get("party_type"),
"party": d.get("party"),
"account_currency": d.get("account_currency"),
"balance": d.get("balance_in_account_currency"),
reverse_dr_or_cr: abs(d.get("balance_in_account_currency")),
"exchange_rate": d.get("current_exchange_rate"),
"balance": flt(d.get("balance_in_account_currency"), d.precision("balance_in_account_currency")),
reverse_dr_or_cr: flt(abs(d.get("balance_in_account_currency")), d.precision("balance_in_account_currency")),
"exchange_rate": flt(d.get("current_exchange_rate"), d.precision("current_exchange_rate")),
"reference_type": "Exchange Rate Revaluation",
"reference_name": self.name
})
@@ -166,9 +167,9 @@ def get_account_details(account, company, posting_date, party_type=None, party=N
account_details = {}
company_currency = erpnext.get_company_currency(company)
balance = get_balance_on(account, party_type=party_type, party=party, in_account_currency=False)
balance = get_balance_on(account, date=posting_date, party_type=party_type, party=party, in_account_currency=False)
if balance:
balance_in_account_currency = get_balance_on(account, party_type=party_type, party=party)
balance_in_account_currency = get_balance_on(account, date=posting_date, party_type=party_type, party=party)
current_exchange_rate = balance / balance_in_account_currency if balance_in_account_currency else 0
new_exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
new_balance_in_base_currency = balance_in_account_currency * new_exchange_rate

View File

@@ -3,11 +3,13 @@
from __future__ import unicode_literals
import frappe, unittest
import unittest
import frappe
from frappe.utils import now_datetime
from erpnext.accounts.doctype.fiscal_year.fiscal_year import FiscalYearIncorrectDate
test_records = frappe.get_test_records('Fiscal Year')
test_ignore = ["Company"]
class TestFiscalYear(unittest.TestCase):
@@ -23,3 +25,29 @@ class TestFiscalYear(unittest.TestCase):
})
self.assertRaises(FiscalYearIncorrectDate, fy.insert)
def test_record_generator():
test_records = [
{
"doctype": "Fiscal Year",
"year": "_Test Short Fiscal Year 2011",
"is_short_year": 1,
"year_end_date": "2011-04-01",
"year_start_date": "2011-12-31"
}
]
start = 2012
end = now_datetime().year + 5
for year in range(start, end):
test_records.append({
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year {}".format(year),
"year_start_date": "{}-01-01".format(year),
"year_end_date": "{}-12-31".format(year)
})
return test_records
test_records = test_record_generator()

View File

@@ -1,69 +0,0 @@
[
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2012",
"year_end_date": "2012-12-31",
"year_start_date": "2012-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2013",
"year_end_date": "2013-12-31",
"year_start_date": "2013-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2014",
"year_end_date": "2014-12-31",
"year_start_date": "2014-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2015",
"year_end_date": "2015-12-31",
"year_start_date": "2015-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2016",
"year_end_date": "2016-12-31",
"year_start_date": "2016-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2017",
"year_end_date": "2017-12-31",
"year_start_date": "2017-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2018",
"year_end_date": "2018-12-31",
"year_start_date": "2018-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2019",
"year_end_date": "2019-12-31",
"year_start_date": "2019-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2020",
"year_end_date": "2020-12-31",
"year_start_date": "2020-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2021",
"year_end_date": "2021-12-31",
"year_start_date": "2021-01-01"
},
{
"doctype": "Fiscal Year",
"year": "_Test Short Fiscal Year 2021",
"is_short_year": 1,
"year_end_date": "2021-12-31",
"year_start_date": "2021-04-01"
}
]

View File

@@ -97,8 +97,7 @@ class GLEntry(Document):
def check_pl_account(self):
if self.is_opening=='Yes' and \
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss" and \
self.voucher_type not in ['Purchase Invoice', 'Sales Invoice']:
frappe.db.get_value("Account", self.account, "report_type")=="Profit and Loss":
frappe.throw(_("{0} {1}: 'Profit and Loss' type account {2} not allowed in Opening Entry")
.format(self.voucher_type, self.voucher_no, self.account))
@@ -294,4 +293,8 @@ def rename_temporarily_named_docs(doctype):
oldname = doc.name
set_name_from_naming_options(frappe.get_meta(doctype).autoname, doc)
newname = doc.name
frappe.db.sql("""UPDATE `tab{}` SET name = %s, to_rename = 0 where name = %s""".format(doctype), (newname, oldname))
frappe.db.sql(
"UPDATE `tab{}` SET name = %s, to_rename = 0 where name = %s".format(doctype),
(newname, oldname),
auto_commit=True
)

View File

@@ -29,7 +29,11 @@ class JournalEntry(AccountsController):
self.validate_entries_for_advance()
self.validate_multi_currency()
self.set_amounts_in_company_currency()
self.validate_total_debit_and_credit()
# Do not validate while importing via data import
if not frappe.flags.in_import:
self.validate_total_debit_and_credit()
self.validate_against_jv()
self.validate_reference_doc()
self.set_against_account()
@@ -207,11 +211,11 @@ class JournalEntry(AccountsController):
if d.reference_type=="Journal Entry":
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0:
frappe.throw(_("For {0}, only credit accounts can be linked against another debit entry")
.format(d.account))
frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets credited")
.format(d.idx, d.account))
elif account_root_type == "Liability" and flt(d.credit) > 0:
frappe.throw(_("For {0}, only debit accounts can be linked against another credit entry")
.format(d.account))
frappe.throw(_("Row #{0}: For {1}, you can select reference document only if account gets debited")
.format(d.idx, d.account))
if d.reference_name == self.name:
frappe.throw(_("You can not enter current voucher in 'Against Journal Entry' column"))
@@ -1047,4 +1051,4 @@ def make_reverse_journal_entry(source_name, target_doc=None):
},
}, target_doc)
return doclist
return doclist

View File

@@ -593,12 +593,22 @@ frappe.ui.form.on('Payment Entry', {
{fieldtype:"Column Break"},
{fieldtype:"Float", label: __("Less Than Amount"), fieldname:"outstanding_amt_less_than"},
{fieldtype:"Section Break"},
{fieldtype:"Link", label:__("Cost Center"), fieldname:"cost_center", options:"Cost Center",
"get_query": function() {
return {
"filters": {"company": frm.doc.company}
}
}
},
{fieldtype:"Column Break"},
{fieldtype:"Section Break"},
{fieldtype:"Check", label: __("Allocate Payment Amount"), fieldname:"allocate_payment_amount", default:1},
];
frappe.prompt(fields, function(filters){
frappe.flags.allocate_payment_amount = true;
frm.events.validate_filters_data(frm, filters);
frm.doc.cost_center = filters.cost_center;
frm.events.get_outstanding_documents(frm, filters);
}, __("Filters"), __("Get Outstanding Documents"));
},
@@ -1041,18 +1051,10 @@ frappe.ui.form.on('Payment Entry', {
},
callback: function(r, rt) {
if(r.message) {
frappe.run_serially([
() => {
frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
frm.set_value("party_balance", r.message.party_balance);
},
() => {
if(frm.doc.payment_type != "Internal") {
frm.clear_table("references");
}
}
]);
}
}

View File

@@ -531,7 +531,8 @@
"fieldtype": "Data",
"hidden": 1,
"label": "Title",
"print_hide": 1
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "party",
@@ -575,7 +576,7 @@
}
],
"is_submittable": 1,
"modified": "2019-11-06 12:59:43.151721",
"modified": "2021-03-10 13:05:16.958866",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
@@ -619,4 +620,4 @@
"sort_order": "DESC",
"title_field": "title",
"track_changes": 1
}
}

View File

@@ -441,6 +441,10 @@ class PaymentEntry(AccountsController):
.format(total_negative_outstanding), InvalidPaymentEntry)
def set_title(self):
if frappe.flags.in_import and self.title:
# do not set title dynamically if title exists during data import.
return
if self.payment_type in ("Receive", "Pay"):
self.title = self.party
else:

View File

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

View File

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

View File

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

View File

@@ -131,7 +131,7 @@ class PricingRule(Document):
for d in self.items:
max_discount = frappe.get_cached_value("Item", d.item_code, "max_discount")
if max_discount and flt(self.discount_percentage) > flt(max_discount):
throw(_("Max discount allowed for item: {0} is {1}%").format(self.item_code, max_discount))
throw(_("Max discount allowed for item: {0} is {1}%").format(d.item_code, max_discount))
def validate_price_list_with_currency(self):
if self.currency and self.for_price_list:
@@ -330,13 +330,17 @@ def get_pricing_rule_details(args, pricing_rule):
def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
or (pricing_rule.margin_type == 'Percentage')):
item_details.margin_type = pricing_rule.margin_type
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
else:
item_details.margin_type = None
item_details.margin_rate_or_amount = 0.0
for apply_on in ['Percentage', 'Amount']:
if pricing_rule.margin_type != apply_on:
continue
field = 'margin_rate_or_amount'
if field not in item_details:
item_details.setdefault(field, 0)
item_details.setdefault('margin_type', apply_on)
item_details[field] += (pricing_rule.get(field, 0)
if pricing_rule else args.get(field, 0))
if pricing_rule.rate_or_discount == 'Rate':
pricing_rule_rate = 0.0

View File

@@ -467,7 +467,7 @@ def apply_pricing_rule_on_transaction(doc):
if not d.get(pr_field): continue
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
if d.validate_applied_rule and doc.get(field) is not None and doc.get(field) < d.get(pr_field):
frappe.msgprint(_("User has not applied rule on the invoice {0}")
.format(doc.name))
else:

View File

@@ -509,7 +509,7 @@ frappe.ui.form.on("Purchase Invoice", {
},
onload: function(frm) {
if(frm.doc.__onload) {
if(frm.doc.__onload && frm.is_new()) {
if(frm.doc.supplier) {
frm.doc.apply_tds = frm.doc.__onload.supplier_tds ? 1 : 0;
}

View File

@@ -247,8 +247,15 @@ class PurchaseInvoice(BuyingController):
else:
item.expense_account = stock_not_billed_account
elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
asset_category_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
company = self.company)
if not asset_category_account:
form_link = get_link_to_form('Asset Category', asset_category)
throw(
_("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company),
title=_("Missing Account")
)
item.expense_account = asset_category_account
elif item.is_fixed_asset and item.pr_detail:
item.expense_account = asset_received_but_not_billed
elif not item.expense_account and for_validate:

View File

@@ -43,7 +43,7 @@
}
],
"grand_total": 0,
"naming_series": "_T-BILL",
"naming_series": "T-PINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",
@@ -168,7 +168,7 @@
}
],
"grand_total": 0,
"naming_series": "_T-Purchase Invoice-",
"naming_series": "T-PINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",

View File

@@ -825,45 +825,43 @@ frappe.ui.form.on('Sales Invoice', {
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_invoice_discounting",
frm: frm
});
}
})
},
frappe.ui.form.on('Sales Invoice Timesheet', {
calculate_timesheet_totals: function(frm) {
frm.set_value("total_billing_amount",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_amount"] || 0.0), 0.0));
frm.set_value("total_billing_hours",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_hours"] || 0.0), 0.0));
}
});
frappe.ui.form.on("Sales Invoice Timesheet", {
time_sheet: function(frm, cdt, cdn){
var d = locals[cdt][cdn];
if(d.time_sheet) {
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data",
args: {
'name': d.time_sheet,
'project': frm.doc.project || null
"name": d.time_sheet,
"project": frm.doc.project || null
},
callback: function(r, rt) {
callback: function(r) {
if(r.message){
data = r.message;
frappe.model.set_value(cdt, cdn, "billing_hours", data.billing_hours);
frappe.model.set_value(cdt, cdn, "billing_amount", data.billing_amount);
frappe.model.set_value(cdt, cdn, "timesheet_detail", data.timesheet_detail);
calculate_total_billing_amount(frm)
frappe.model.set_value(cdt, cdn, "billing_hours", r.message.billing_hours);
frappe.model.set_value(cdt, cdn, "billing_amount", r.message.billing_amount);
frappe.model.set_value(cdt, cdn, "timesheet_detail", r.message.timesheet_detail);
frm.trigger("calculate_timesheet_totals");
}
}
})
});
}
},
timesheets_remove: function(frm, cdt, cdn) {
frm.trigger("calculate_timesheet_totals");
}
})
});
var calculate_total_billing_amount = function(frm) {
var doc = frm.doc;
doc.total_billing_amount = 0.0
if(doc.timesheets) {
$.each(doc.timesheets, function(index, data){
doc.total_billing_amount += data.billing_amount
})
}
refresh_field('total_billing_amount')
}
var select_loyalty_program = function(frm, loyalty_programs) {
var dialog = new frappe.ui.Dialog({

View File

@@ -69,6 +69,7 @@
"time_sheet_list",
"timesheets",
"total_billing_amount",
"total_billing_hours",
"section_break_30",
"total_qty",
"base_total",
@@ -1564,12 +1565,20 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "total_billing_hours",
"fieldtype": "Float",
"label": "Total Billing Hours",
"print_hide": 1,
"read_only": 1
}
],
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
"modified": "2020-07-01 12:41:29.484813",
"modified": "2021-07-26 14:01:34.605644",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -450,7 +450,7 @@ class SalesInvoice(SellingController):
# set pos values in items
for item in self.get("items"):
if item.get('item_code'):
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos)
profile_details = get_pos_profile_item_details(pos, frappe._dict(item.as_dict()), pos, update_data=True)
for fname, val in iteritems(profile_details):
if (not for_validate) or (for_validate and not item.get(fname)):
item.set(fname, val)
@@ -539,7 +539,7 @@ class SalesInvoice(SellingController):
def add_remarks(self):
if not self.remarks:
if self.po_no and self.po_date:
self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
self.remarks = _("Against Customer Order {0} dated {1}").format(self.po_no,
formatdate(self.po_date))
else:
self.remarks = _("No Remarks")
@@ -683,12 +683,11 @@ class SalesInvoice(SellingController):
self.calculate_billing_amount_for_timesheet()
def calculate_billing_amount_for_timesheet(self):
total_billing_amount = 0.0
for data in self.timesheets:
if data.billing_amount:
total_billing_amount += data.billing_amount
def timesheet_sum(field):
return sum((ts.get(field) or 0.0) for ts in self.timesheets)
self.total_billing_amount = total_billing_amount
self.total_billing_amount = timesheet_sum("billing_amount")
self.total_billing_hours = timesheet_sum("billing_hours")
def get_warehouse(self):
user_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Profile`

View File

@@ -30,7 +30,7 @@
"base_grand_total": 561.8,
"grand_total": 561.8,
"is_pos": 0,
"naming_series": "_T-Sales Invoice-",
"naming_series": "T-SINV-",
"base_net_total": 500.0,
"taxes": [
{
@@ -103,7 +103,7 @@
"base_grand_total": 630.0,
"grand_total": 630.0,
"is_pos": 0,
"naming_series": "_T-Sales Invoice-",
"naming_series": "T-SINV-",
"base_net_total": 500.0,
"taxes": [
{
@@ -174,7 +174,7 @@
],
"grand_total": 0,
"is_pos": 0,
"naming_series": "_T-Sales Invoice-",
"naming_series": "T-SINV-",
"taxes": [
{
"account_head": "_Test Account Shipping Charges - _TC",
@@ -300,7 +300,7 @@
],
"grand_total": 0,
"is_pos": 0,
"naming_series": "_T-Sales Invoice-",
"naming_series": "T-SINV-",
"taxes": [
{
"account_head": "_Test Account Excise Duty - _TC",

View File

@@ -1860,7 +1860,17 @@ class TestSalesInvoice(unittest.TestCase):
def test_einvoice_submission_without_irn(self):
# init
frappe.db.set_value('E Invoice Settings', 'E Invoice Settings', 'enable', 1)
einvoice_settings = frappe.get_doc('E Invoice Settings')
einvoice_settings.enable = 1
einvoice_settings.applicable_from = nowdate()
einvoice_settings.append('credentials', {
'company': '_Test Company',
'gstin': '27AAECE4835E1ZR',
'username': 'test',
'password': 'test'
})
einvoice_settings.save()
country = frappe.flags.country
frappe.flags.country = 'India'
@@ -1871,7 +1881,8 @@ class TestSalesInvoice(unittest.TestCase):
si.submit()
# reset
frappe.db.set_value('E Invoice Settings', 'E Invoice Settings', 'enable', 0)
einvoice_settings = frappe.get_doc('E Invoice Settings')
einvoice_settings.enable = 0
frappe.flags.country = country
def test_einvoice_json(self):
@@ -2063,6 +2074,7 @@ def create_sales_invoice(**args):
si.return_against = args.return_against
si.currency=args.currency or "INR"
si.conversion_rate = args.conversion_rate or 1
si.naming_series = args.naming_series or "T-SINV-"
si.append("items", {
"item_code": args.item or args.item_code or "_Test Item",

View File

@@ -169,7 +169,7 @@ class ShareTransfer(Document):
def folio_no_validation(self):
shareholders = ['from_shareholder', 'to_shareholder']
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not '']
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) != '']
for shareholder in shareholders:
doc = self.get_shareholder_doc(self.get(shareholder))
if doc.company != self.company:

View File

@@ -30,6 +30,7 @@
"additional_discount_percentage",
"additional_discount_amount",
"sb_3",
"submit_invoice",
"invoices",
"accounting_dimensions_section",
"dimension_col_break"
@@ -202,9 +203,15 @@
"fieldname": "generate_new_invoices_past_due_date",
"fieldtype": "Check",
"label": "Generate New Invoices Past Due Date"
},
{
"default": "1",
"fieldname": "submit_invoice",
"fieldtype": "Check",
"label": "Submit Invoice Automatically"
}
],
"modified": "2020-11-29 22:46:14.879289",
"modified": "2021-05-03 13:35:21.422940",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",

View File

@@ -288,8 +288,11 @@ class Subscription(Document):
invoice.to_date = self.current_invoice_end
invoice.flags.ignore_mandatory = True
invoice.set_missing_values()
invoice.save()
invoice.submit()
if self.submit_invoice:
invoice.submit()
return invoice

View File

@@ -163,7 +163,7 @@ def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_detai
debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
supplier_credit_amount -= debit_note_amount
if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
if ((tax_details.get('threshold', 0) and net_total >= tax_details.threshold)
or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,

View File

@@ -83,47 +83,6 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in invoices:
d.cancel()
def test_single_threshold_tds_with_previous_vouchers(self):
invoices = []
frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS")
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
self.assertEqual(pi.taxes_and_charges_deducted, 2000)
self.assertEqual(pi.grand_total, 8000)
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
def test_single_threshold_tds_with_previous_vouchers_and_no_tds(self):
invoices = []
frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS")
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
# TDS not applied
pi = create_purchase_invoice(supplier="Test TDS Supplier2", do_not_apply_tds=True)
pi.submit()
invoices.append(pi)
pi = create_purchase_invoice(supplier="Test TDS Supplier2")
pi.submit()
invoices.append(pi)
self.assertEqual(pi.taxes_and_charges_deducted, 2000)
self.assertEqual(pi.grand_total, 8000)
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
def create_purchase_invoice(**args):
# return sales invoice doc object
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})

View File

@@ -147,7 +147,7 @@ def make_entry(args, adv_adj, update_outstanding, from_repost=False):
gle.submit()
def validate_account_for_perpetual_inventory(gl_map):
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)) and gl_map[0].voucher_type=="Journal Entry":
account_list = [gl_entries.account for gl_entries in gl_map]
aii_accounts = [d.name for d in frappe.get_all("Account",
@@ -160,13 +160,12 @@ def validate_account_for_perpetual_inventory(gl_map):
account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
gl_map[0].posting_date, gl_map[0].company)
if gl_map[0].voucher_type=="Journal Entry":
# In case of Journal Entry, there are no corresponding SL entries,
# hence deducting currency amount
account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit)
if account_bal == stock_bal:
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(account), StockAccountInvalidTransaction)
# In case of Journal Entry, there are no corresponding SL entries,
# hence deducting currency amount
account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit)
if account_bal == stock_bal:
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(account), StockAccountInvalidTransaction)
# This has been comment for a temporary, will add this code again on release of immutable ledger
# elif account_bal != stock_bal:
@@ -240,10 +239,10 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
for d in gl_map:
if d.account == round_off_account:
round_off_gle = d
if d.debit_in_account_currency:
debit_credit_diff -= flt(d.debit_in_account_currency)
if d.debit:
debit_credit_diff -= flt(d.debit)
else:
debit_credit_diff += flt(d.credit_in_account_currency)
debit_credit_diff += flt(d.credit)
round_off_account_exists = True
if round_off_account_exists and abs(debit_credit_diff) <= (1.0 / (10**precision)):
@@ -252,7 +251,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
if not round_off_gle:
for k in ["voucher_type", "voucher_no", "company",
"posting_date", "remarks", "is_opening"]:
"posting_date", "remarks"]:
round_off_gle[k] = gl_map[0][k]
round_off_gle.update({
@@ -264,6 +263,7 @@ def make_round_off_gle(gl_map, debit_credit_diff, precision):
"cost_center": round_off_cost_center,
"party_type": None,
"party": None,
"is_opening": "No",
"against_voucher_type": None,
"against_voucher": None
})
@@ -293,7 +293,8 @@ def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
select account, posting_date, party_type, party, cost_center, fiscal_year,voucher_type,
voucher_no, against_voucher_type, against_voucher, cost_center, company
from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
where voucher_type=%s and voucher_no=%s
for update""", (voucher_type, voucher_no), as_dict=True)
if gl_entries:
validate_accounting_period(gl_entries)

View File

@@ -1,7 +1,8 @@
{%- from "templates/print_formats/standard_macros.html" import add_header, render_field, print_value -%}
{%- set einvoice = json.loads(doc.signed_einvoice) -%}
<div class="page-break">
{% if doc.signed_einvoice %}
{%- set einvoice = json.loads(doc.signed_einvoice) -%}
<div {% if print_settings.repeat_header_footer %} id="header-html" class="hidden-pdf" {% endif %}>
{% if letter_head and not no_letterhead %}
<div class="letter-head">{{ letter_head }}</div>
@@ -163,4 +164,10 @@
</tbody>
</table>
</div>
</div>
{% else %}
<div class="text-center" style="color: #98A1A9; font-size: 14px;">
You must generate IRN before you can preview GST E-Invoice.
</div>
{% endif %}
</div>

View File

@@ -165,7 +165,7 @@ def add_data_for_operating_activities(
if profit_data:
profit_data.update({
"indent": 1,
"parent_account": get_mapper_for(light_mappers, position=0)['section_header']
"parent_account": get_mapper_for(light_mappers, position=1)['section_header']
})
data.append(profit_data)
section_data.append(profit_data)
@@ -312,10 +312,10 @@ def add_data_for_other_activities(
def compute_data(filters, company_currency, profit_data, period_list, light_mappers, full_mapper):
data = []
operating_activities_mapper = get_mapper_for(light_mappers, position=0)
operating_activities_mapper = get_mapper_for(light_mappers, position=1)
other_mappers = [
get_mapper_for(light_mappers, position=1),
get_mapper_for(light_mappers, position=2)
get_mapper_for(light_mappers, position=2),
get_mapper_for(light_mappers, position=3)
]
if operating_activities_mapper:
@@ -396,7 +396,7 @@ def _get_account_type_based_data(filters, account_names, period_list, accumulate
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s
where company=%s and posting_date >= %s and posting_date <= %s
and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE name IN (%s)
OR parent_account IN (%s))
@@ -405,7 +405,7 @@ def _get_account_type_based_data(filters, account_names, period_list, accumulate
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
where company=%s and posting_date >= %s and posting_date <= %s
where company=%s and posting_date >= %s and posting_date <= %s
and voucher_type != 'Period Closing Voucher'
and account in ( SELECT name FROM tabAccount WHERE name IN (%s)
OR parent_account IN (%s))

View File

@@ -224,8 +224,7 @@ def get_company_currency(filters=None):
def calculate_values(accounts_by_name, gl_entries_by_account, companies, fiscal_year, filters):
for entries in gl_entries_by_account.values():
for entry in entries:
key = entry.account_number or entry.account_name
d = accounts_by_name.get(key)
d = accounts_by_name.get(entry.account_name)
if d:
for company in companies:
# check if posting date is within the period
@@ -240,7 +239,8 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies):
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
if d.parent_account:
account = d.parent_account.split('-')[0].strip()
account = d.parent_account_name
if not accounts_by_name.get(account):
continue
@@ -251,16 +251,34 @@ def accumulate_values_into_parents(accounts, accounts_by_name, companies):
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)
if not accounts:
return None, None
accounts = update_parent_account_names(accounts)
accounts, accounts_by_name, parent_children_map = filter_accounts(accounts)
return accounts, accounts_by_name
def update_parent_account_names(accounts):
"""Update parent_account_name in accounts list.
parent_name is `name` of parent account which could have other prefix
of account_number and suffix of company abbr. This function adds key called
`parent_account_name` which does not have such prefix/suffix.
"""
name_to_account_map = { d.name : d.account_name for d in accounts }
for account in accounts:
if account.parent_account:
account["parent_account_name"] = name_to_account_map[account.parent_account]
return accounts
def get_companies(filters):
companies = {}
all_companies = get_subsidiary_companies(filters.get('company'))
@@ -367,9 +385,9 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
convert_to_presentation_currency(gl_entries, currency_info)
for entry in gl_entries:
key = entry.account_number or entry.account_name
validate_entries(key, entry, accounts_by_name, accounts)
gl_entries_by_account.setdefault(key, []).append(entry)
account_name = entry.account_name
validate_entries(account_name, entry, accounts_by_name, accounts)
gl_entries_by_account.setdefault(account_name, []).append(entry)
return gl_entries_by_account
@@ -438,8 +456,7 @@ def filter_accounts(accounts, depth=10):
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
key = d.account_number or d.account_name
accounts_by_name[key] = d
accounts_by_name[d.account_name] = d
parent_children_map.setdefault(d.parent_account or None, []).append(d)
filtered_accounts = []

View File

@@ -36,5 +36,20 @@ frappe.query_reports["Gross Profit"] = {
"options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject",
"default": "Invoice"
},
]
],
"tree": true,
"name_field": "parent",
"parent_field": "parent_invoice",
"initial_depth": 3,
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (data && data.indent == 0.0) {
value = $(`<span>${value}</span>`);
var $value = $(value).css("font-weight", "bold");
value = $value.wrap("<p></p>").parent().html();
}
return value;
},
}

View File

@@ -1,16 +1,20 @@
{
"add_total_row": 1,
"add_total_row": 0,
"columns": [],
"creation": "2013-02-25 17:03:34",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 3,
"is_standard": "Yes",
"modified": "2020-08-13 11:26:39.112352",
"modified": "2021-08-19 18:57:07.468202",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Gross Profit",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Sales Invoice",
"report_name": "Gross Profit",
"report_type": "Script Report",

View File

@@ -41,16 +41,44 @@ def execute(filters=None):
columns = get_columns(group_wise_columns, filters)
for src in gross_profit_data.grouped_data:
if filters.group_by == 'Invoice':
get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data)
else:
get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data)
return columns, data
def get_data_when_grouped_by_invoice(columns, gross_profit_data, filters, group_wise_columns, data):
column_names = get_column_names()
# to display item as Item Code: Item Name
columns[0] = 'Sales Invoice:Link/Item:300'
# removing Item Code and Item Name columns
del columns[4:6]
for src in gross_profit_data.si_list:
row = frappe._dict()
row.indent = src.indent
row.parent_invoice = src.parent_invoice
row.currency = filters.currency
for col in group_wise_columns.get(scrub(filters.group_by)):
row[column_names[col]] = src.get(col)
data.append(row)
def get_data_when_not_grouped_by_invoice(gross_profit_data, filters, group_wise_columns, data):
for idx, src in enumerate(gross_profit_data.grouped_data):
row = []
for col in group_wise_columns.get(scrub(filters.group_by)):
row.append(src.get(col))
row.append(filters.currency)
if idx == len(gross_profit_data.grouped_data)-1:
row[0] = frappe.bold("Total")
data.append(row)
return columns, data
def get_columns(group_wise_columns, filters):
columns = []
column_map = frappe._dict({
@@ -91,12 +119,38 @@ def get_columns(group_wise_columns, filters):
return columns
def get_column_names():
return frappe._dict({
'parent': 'sales_invoice',
'customer': 'customer',
'customer_group': 'customer_group',
'posting_date': 'posting_date',
'item_code': 'item_code',
'item_name': 'item_name',
'item_group': 'item_group',
'brand': 'brand',
'description': 'description',
'warehouse': 'warehouse',
'qty': 'qty',
'base_rate': 'avg._selling_rate',
'buying_rate': 'valuation_rate',
'base_amount': 'selling_amount',
'buying_amount': 'buying_amount',
'gross_profit': 'gross_profit',
'gross_profit_percent': 'gross_profit_%',
'project': 'project'
})
class GrossProfitGenerator(object):
def __init__(self, filters=None):
self.data = []
self.average_buying_rate = {}
self.filters = frappe._dict(filters)
self.load_invoice_items()
if filters.group_by == 'Invoice':
self.group_items_by_invoice()
self.load_stock_ledger_entries()
self.load_product_bundle()
self.load_non_stock_items()
@@ -110,7 +164,12 @@ class GrossProfitGenerator(object):
self.currency_precision = cint(frappe.db.get_default("currency_precision")) or 3
self.float_precision = cint(frappe.db.get_default("float_precision")) or 2
for row in self.si_list:
grouped_by_invoice = True if self.filters.get("group_by") == "Invoice" else False
if grouped_by_invoice:
buying_amount = 0
for row in reversed(self.si_list):
if self.skip_row(row, self.product_bundles):
continue
@@ -132,12 +191,20 @@ class GrossProfitGenerator(object):
row.buying_amount = flt(self.get_buying_amount(row, row.item_code),
self.currency_precision)
if grouped_by_invoice:
if row.indent == 1.0:
buying_amount += row.buying_amount
elif row.indent == 0.0:
row.buying_amount = buying_amount
buying_amount = 0
# get buying rate
if row.qty:
row.buying_rate = flt(row.buying_amount / row.qty, self.float_precision)
row.base_rate = flt(row.base_amount / row.qty, self.float_precision)
else:
row.buying_rate, row.base_rate = 0.0, 0.0
if self.is_not_invoice_row(row):
row.buying_rate, row.base_rate = 0.0, 0.0
# calculate gross profit
row.gross_profit = flt(row.base_amount - row.buying_amount, self.currency_precision)
@@ -154,6 +221,15 @@ class GrossProfitGenerator(object):
def get_average_rate_based_on_group_by(self):
# sum buying / selling totals for group
self.totals = frappe._dict(
qty=0,
base_amount=0,
buying_amount=0,
gross_profit=0,
gross_profit_percent=0,
base_rate=0,
buying_rate=0
)
for key in list(self.grouped):
if self.filters.get("group_by") != "Invoice":
for i, row in enumerate(self.grouped[key]):
@@ -165,6 +241,7 @@ class GrossProfitGenerator(object):
new_row.base_amount += flt(row.base_amount, self.currency_precision)
new_row = self.set_average_rate(new_row)
self.grouped_data.append(new_row)
self.add_to_totals(new_row)
else:
for i, row in enumerate(self.grouped[key]):
if row.parent in self.returned_invoices \
@@ -173,19 +250,32 @@ class GrossProfitGenerator(object):
for returned_item_row in returned_item_rows:
row.qty += returned_item_row.qty
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
row.buying_amount = flt(row.qty * row.buying_rate, self.currency_precision)
if row.qty or row.base_amount:
row.buying_amount = flt(flt(row.qty) * flt(row.buying_rate), self.currency_precision)
if (flt(row.qty) or row.base_amount) and self.is_not_invoice_row(row):
row = self.set_average_rate(row)
self.grouped_data.append(row)
self.add_to_totals(row)
self.set_average_gross_profit(self.totals)
self.grouped_data.append(self.totals)
def is_not_invoice_row(self, row):
return (self.filters.get("group_by") == "Invoice" and row.indent != 0.0) or self.filters.get("group_by") != "Invoice"
def set_average_rate(self, new_row):
self.set_average_gross_profit(new_row)
new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, self.float_precision) if new_row.qty else 0
new_row.base_rate = flt(new_row.base_amount / new_row.qty, self.float_precision) if new_row.qty else 0
return new_row
def set_average_gross_profit(self, new_row):
new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount, self.currency_precision)
new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0), self.currency_precision) \
if new_row.base_amount else 0
new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, self.float_precision) if new_row.qty else 0
new_row.base_rate = flt(new_row.base_amount / new_row.qty, self.float_precision) if new_row.qty else 0
return new_row
def add_to_totals(self, new_row):
for key in self.totals:
if new_row.get(key):
self.totals[key] += new_row[key]
def get_returned_invoice_items(self):
returned_invoices = frappe.db.sql("""
@@ -334,6 +424,109 @@ class GrossProfitGenerator(object):
.format(conditions=conditions, sales_person_cols=sales_person_cols,
sales_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice')), self.filters, as_dict=1)
def group_items_by_invoice(self):
"""
Turns list of Sales Invoice Items to a tree of Sales Invoices with their Items as children.
"""
parents = []
for row in self.si_list:
if row.parent not in parents:
parents.append(row.parent)
parents_index = 0
for index, row in enumerate(self.si_list):
if parents_index < len(parents) and row.parent == parents[parents_index]:
invoice = self.get_invoice_row(row)
self.si_list.insert(index, invoice)
parents_index += 1
else:
# skipping the bundle items rows
if not row.indent:
row.indent = 1.0
row.parent_invoice = row.parent
row.parent = row.item_code
if frappe.db.exists('Product Bundle', row.item_code):
self.add_bundle_items(row, index)
def get_invoice_row(self, row):
return frappe._dict({
'parent_invoice': "",
'indent': 0.0,
'parent': row.parent,
'posting_date': row.posting_date,
'posting_time': row.posting_time,
'project': row.project,
'update_stock': row.update_stock,
'customer': row.customer,
'customer_group': row.customer_group,
'item_code': None,
'item_name': None,
'description': None,
'warehouse': None,
'item_group': None,
'brand': None,
'dn_detail': None,
'delivery_note': None,
'qty': None,
'item_row': None,
'is_return': row.is_return,
'cost_center': row.cost_center,
'base_net_amount': frappe.db.get_value('Sales Invoice', row.parent, 'base_net_total')
})
def add_bundle_items(self, product_bundle, index):
bundle_items = self.get_bundle_items(product_bundle)
for i, item in enumerate(bundle_items):
bundle_item = self.get_bundle_item_row(product_bundle, item)
self.si_list.insert((index+i+1), bundle_item)
def get_bundle_items(self, product_bundle):
return frappe.get_all(
'Product Bundle Item',
filters = {
'parent': product_bundle.item_code
},
fields = ['item_code', 'qty']
)
def get_bundle_item_row(self, product_bundle, item):
item_name, description, item_group, brand = self.get_bundle_item_details(item.item_code)
return frappe._dict({
'parent_invoice': product_bundle.item_code,
'indent': product_bundle.indent + 1,
'parent': item.item_code,
'posting_date': product_bundle.posting_date,
'posting_time': product_bundle.posting_time,
'project': product_bundle.project,
'customer': product_bundle.customer,
'customer_group': product_bundle.customer_group,
'item_code': item.item_code,
'item_name': item_name,
'description': description,
'warehouse': product_bundle.warehouse,
'item_group': item_group,
'brand': brand,
'dn_detail': product_bundle.dn_detail,
'delivery_note': product_bundle.delivery_note,
'qty': (flt(product_bundle.qty) * flt(item.qty)),
'item_row': None,
'is_return': product_bundle.is_return,
'cost_center': product_bundle.cost_center
})
def get_bundle_item_details(self, item_code):
return frappe.db.get_value(
'Item',
item_code,
['item_name', 'description', 'item_group', 'brand']
)
def load_stock_ledger_entries(self):
res = frappe.db.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, stock_value, warehouse, actual_qty as qty

View File

@@ -78,6 +78,7 @@ frappe.ui.form.on('Asset', {
frappe.ui.form.trigger("Asset", "is_existing_asset");
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
frm.events.make_schedules_editable(frm);
frm.trigger("toggle_make_depreciation_entry");
if (frm.doc.docstatus==1) {
if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) {
@@ -141,6 +142,18 @@ frappe.ui.form.on('Asset', {
}
},
toggle_make_depreciation_entry: function(frm) {
if (frm.doc.calculate_depreciation){
if (in_list(["Submitted", "Partially Depreciated"], frm.doc.status)){
frm.fields_dict['schedules'].grid.set_column_disp('make_depreciation_entry', true);
} else {
frm.fields_dict['schedules'].grid.set_column_disp('make_depreciation_entry', false);
}
frm.refresh_field('schedules');
}
},
toggle_reference_doc: function(frm) {
if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
frm.set_df_property('purchase_invoice', 'read_only', 1);

View File

@@ -122,11 +122,6 @@ class Asset(AccountsController):
if self.is_existing_asset:
return
docname = self.purchase_receipt or self.purchase_invoice
if docname:
doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
date = frappe.db.get_value(doctype, docname, 'posting_date')
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
@@ -404,9 +399,10 @@ class Asset(AccountsController):
if accumulated_depreciation_after_full_schedule:
accumulated_depreciation_after_full_schedule = max(accumulated_depreciation_after_full_schedule)
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule),
self.precision('gross_purchase_amount'))
asset_value_after_full_schedule = flt(
flt(self.gross_purchase_amount) -
flt(self.opening_accumulated_depreciation) -
flt(accumulated_depreciation_after_full_schedule), self.precision('gross_purchase_amount'))
if (row.expected_value_after_useful_life and
row.expected_value_after_useful_life < asset_value_after_full_schedule):

View File

@@ -34,6 +34,8 @@ def make_depreciation_entry(asset_name, date=None):
date = today()
asset = frappe.get_doc("Asset", asset_name)
validate_asset(asset)
fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account = \
get_depreciation_accounts(asset)
@@ -59,7 +61,7 @@ def make_depreciation_entry(asset_name, date=None):
"credit_in_account_currency": d.depreciation_amount,
"reference_type": "Asset",
"reference_name": asset.name,
"cost_center": ""
"cost_center": depreciation_cost_center
}
debit_entry = {
@@ -101,6 +103,10 @@ def make_depreciation_entry(asset_name, date=None):
return asset
def validate_asset(asset):
if asset.status not in ['Submitted', 'Partially Depreciated']:
frappe.throw(_("Cannot depreciate {0} Asset").format(asset.status))
def get_depreciation_accounts(asset):
fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None

View File

@@ -3,6 +3,7 @@
"description": "Settings for Buying Module",
"doctype": "DocType",
"document_type": "Other",
"engine": "InnoDB",
"field_order": [
"supp_master_name",
"supplier_group",
@@ -92,7 +93,7 @@
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"modified": "2019-08-20 13:13:09.055189",
"modified": "2021-03-02 18:16:03.947813",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
@@ -107,5 +108,8 @@
"share": 1,
"write": 1
}
]
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -355,7 +355,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
per_ordered: ["<", 100],
}
})
}, __("Get items from"));

View File

@@ -366,7 +366,6 @@ def make_purchase_receipt(source_name, target_doc=None):
"Purchase Order": {
"doctype": "Purchase Receipt",
"field_map": {
"per_billed": "per_billed",
"supplier_warehouse":"supplier_warehouse"
},
"validation": {

View File

@@ -271,7 +271,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99]
per_ordered: ["<", 100]
}
})
}, __("Get items from"));
@@ -316,7 +316,7 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99]
per_ordered: ["<", 100]
}
});
$(btn).done_working();

View File

@@ -279,19 +279,21 @@ def add_items(sq_doc, supplier, items):
create_rfq_items(sq_doc, supplier, data)
def create_rfq_items(sq_doc, supplier, data):
sq_doc.append('items', {
"item_code": data.item_code,
"item_name": data.item_name,
"description": data.description,
"qty": data.qty,
"rate": data.rate,
"conversion_factor": data.conversion_factor if data.conversion_factor else None,
"supplier_part_no": frappe.db.get_value("Item Supplier", {'parent': data.item_code, 'supplier': supplier}, "supplier_part_no"),
"warehouse": data.warehouse or '',
args = {}
for field in ['item_code', 'item_name', 'description', 'qty', 'rate', 'conversion_factor',
'warehouse', 'material_request', 'material_request_item', 'stock_qty']:
args[field] = data.get(field)
args.update({
"request_for_quotation_item": data.name,
"request_for_quotation": data.parent
"request_for_quotation": data.parent,
"supplier_part_no": frappe.db.get_value("Item Supplier",
{'parent': data.item_code, 'supplier': supplier}, "supplier_part_no")
})
sq_doc.append('items', args)
@frappe.whitelist()
def get_pdf(doctype, name, supplier_idx):
doc = get_rfq_doc(doctype, name, supplier_idx)

View File

@@ -46,7 +46,7 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99]
per_ordered: ["<", 100]
}
})
}, __("Get items from"));

View File

@@ -0,0 +1,34 @@
## Version 12.20.0 Release Notes
### Fixes & Enhancements
- E-invoicing - Validations & tax calculation fixes ([#25315](https://github.com/frappe/erpnext/pull/25315))
- Allow zero valuation in stock reconciliation ([#24986](https://github.com/frappe/erpnext/pull/24986))
- Remove shipping address GSTIN validation for e-invoice ([#25133](https://github.com/frappe/erpnext/pull/25133))
- Allow Item image alt ([#24935](https://github.com/frappe/erpnext/pull/24935))
- Added parent task expected end date validation ([#24889](https://github.com/frappe/erpnext/pull/24889))
- Incorrect Nil Exempt and Non GST amount in GSTR3B report ([#24919](https://github.com/frappe/erpnext/pull/24919))
- Item attributes not editable until refresh ([#24887](https://github.com/frappe/erpnext/pull/24887))
- Create property setters for shorter naming series ([#25134](https://github.com/frappe/erpnext/pull/25134))
- Serial no refresh issue ([#25130](https://github.com/frappe/erpnext/pull/25130))
- Sales Order not saving due type mismatch in promo scheme (#24748) ([#25056](https://github.com/frappe/erpnext/pull/25056))
- TDS check getting checked after reload ([#24974](https://github.com/frappe/erpnext/pull/24974))
- Round total quantity in job card ([#25246](https://github.com/frappe/erpnext/pull/25246))
- santize_for_json is not defined ([#25157](https://github.com/frappe/erpnext/pull/25157))
- Apply single transaction threshold on net_total instead of supplier credit amount ([#25208](https://github.com/frappe/erpnext/pull/25208))
- Zero amount completed delivery notes being shown in Sales Invoice get items ([#25318](https://github.com/frappe/erpnext/pull/25318))
- Error message compensatory leave request ([#25216](https://github.com/frappe/erpnext/pull/25216))
- RCM tax calculation ([#25226](https://github.com/frappe/erpnext/pull/25226))
- Don't delete mode of payment account details while deleting comp… ([#25218](https://github.com/frappe/erpnext/pull/25218))
- Opportunity-quotation mapping order status ([#25002](https://github.com/frappe/erpnext/pull/25002))
- Object referencing same memory address issue ([#25165](https://github.com/frappe/erpnext/pull/25165))
- Validation msg for TransDocNo e-invoicing ([#25120](https://github.com/frappe/erpnext/pull/25120))
- Do not fetch stopped MR in production plan ([#25110](https://github.com/frappe/erpnext/pull/25110))
- Incorrect status creating PR from PO after creating PI ([#25203](https://github.com/frappe/erpnext/pull/25203))
- Remove gst name validation for purchase Invoice ([#25236](https://github.com/frappe/erpnext/pull/25236))
- Assignment Rule Unassign Condition doesn't work ([#24890](https://github.com/frappe/erpnext/pull/24890))
- Place of supply for e-invoicing ([#25149](https://github.com/frappe/erpnext/pull/25149))
- Serial no trim issue ([#24950](https://github.com/frappe/erpnext/pull/24950))
- Commit individual SLE rename for large datasets (v12) ([#25085](https://github.com/frappe/erpnext/pull/25085))
- Incorrect batch picked in subcontracted purchase receipt ([#25169](https://github.com/frappe/erpnext/pull/25169))

View File

@@ -0,0 +1,21 @@
## Version 12.21.0 Release Notes
### Fixes & Enhancements
- Incorrect qty calculated for sub-contracted raw materials in purchase receipt ([#25443](https://github.com/frappe/erpnext/pull/25443))
- Update cost center in the item table fetched from POS Profile in v12 ([#25612](https://github.com/frappe/erpnext/pull/25612))
- Total stock summary report not working ([#25552](https://github.com/frappe/erpnext/pull/25552))
- Timeout error while loading warehouse tree ([#25693](https://github.com/frappe/erpnext/pull/25693))
- RCM rounding precision ([#25410](https://github.com/frappe/erpnext/pull/25410))
- Change subcontracted item display ([#25426](https://github.com/frappe/erpnext/pull/25426))
- Remove invalid changes added due to merge conflict ([#25437](https://github.com/frappe/erpnext/pull/25437))
- Add document type field for e-invoicing (Italy) ([#25420](https://github.com/frappe/erpnext/pull/25420))
- Issue in project custom status ([#25453](https://github.com/frappe/erpnext/pull/25453))
- Employee Separation ([#25504](https://github.com/frappe/erpnext/pull/25504))
- State code for Other Territory ([#25422](https://github.com/frappe/erpnext/pull/25422))
- Remove invalid changes added due to merge conflict ([#25405](https://github.com/frappe/erpnext/pull/25405))
- Check for None in item.schedule_date before setting ([#25589](https://github.com/frappe/erpnext/pull/25589))
- Can't multiply sequence by non-int of type 'float' ([#25385](https://github.com/frappe/erpnext/pull/25385))
- Filter using purpose, make requested changes ([#25388](https://github.com/frappe/erpnext/pull/25388))
- Purchase from registered composition dealer ([#25419](https://github.com/frappe/erpnext/pull/25419))

View File

@@ -0,0 +1,16 @@
## Version 12.22.0 Release Notes
### Fixes & Enhancements
- Cost-center wise period closing entry ([#25930](https://github.com/frappe/erpnext/pull/25930))
- Wrong round off gl entry posted in case of purchase invoice ([#25952](https://github.com/frappe/erpnext/pull/25952))
- Sync shopify customer addresses (#25481) ([#25937](https://github.com/frappe/erpnext/pull/25937))
- Plaid NoneType error ([#25662](https://github.com/frappe/erpnext/pull/25662))
- Cashlfow mapper not showing data ([#25739](https://github.com/frappe/erpnext/pull/25739))
- Update shopify api version (#25600) ([#25939](https://github.com/frappe/erpnext/pull/25939))
- Invalid 'depends_on' expression in opportunity ([#25954](https://github.com/frappe/erpnext/pull/25954))
- Ignore rounding diff while importing JV using data import ([#25715](https://github.com/frappe/erpnext/pull/25715))
- update cost center from POS ([#25972](https://github.com/frappe/erpnext/pull/25972))
- update employee field on renaming employee ([#25958](https://github.com/frappe/erpnext/pull/25958))
- student invalid password reset link ([#25827](https://github.com/frappe/erpnext/pull/25827))
- Backward compatibility for GSTR-1 report ([#25913](https://github.com/frappe/erpnext/pull/25913))

View File

@@ -0,0 +1,20 @@
## Version 12.23.0 Release Notes
### Fixes & Enhancements
- Added Permissions for employee to book an appointment ([#26246](https://github.com/frappe/erpnext/pull/26246))
- New check field in subscriptions for (not) submitting invoices (BP #25394) ([#25560](https://github.com/frappe/erpnext/pull/25560))
- fix(e-invoicing): allow export invoice even if no taxes applied (#26363) ([#26406](https://github.com/frappe/erpnext/pull/26406))
- Omit item discount amount for e-invoicing (#26353) ([#26408](https://github.com/frappe/erpnext/pull/26408))
- fix(plaid): cannot reset plaid link for a bank account ([#26282](https://github.com/frappe/erpnext/pull/26282))
- Job applicant link issue ([#25935](https://github.com/frappe/erpnext/pull/25935))
- LMS progress issue ([#26254](https://github.com/frappe/erpnext/pull/26254))
- Half day to be accounted in its leave type ([#26267](https://github.com/frappe/erpnext/pull/26267))
- Material request status issue ([#26089](https://github.com/frappe/erpnext/pull/26089))
- fix(e-invoicing): service item check ([#26141](https://github.com/frappe/erpnext/pull/26141))
- Invoices can alter profit and loss of a closed year ([#26161](https://github.com/frappe/erpnext/pull/26161))
- Material request and supplier quotation not linked if supplier quotation created from supplier portal ([#26117](https://github.com/frappe/erpnext/pull/26117))
- Update positions in default cashflow mappers ([#26091](https://github.com/frappe/erpnext/pull/26091))
- Staffing plan vacancies data type issue ([#25940](https://github.com/frappe/erpnext/pull/25940))
- Added company filter while fetching loans ([#26296](https://github.com/frappe/erpnext/pull/26296))
- Serial no issue in subcontract purchase receipt ([#26423](https://github.com/frappe/erpnext/pull/26423))
- Fixed rounding off ordered percent to 100 in condition ([#26153](https://github.com/frappe/erpnext/pull/26153))

View File

@@ -1290,6 +1290,11 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
for d in data:
new_child_flag = False
if not d.get("item_code"):
# ignore empty rows
continue
if not d.get("docname"):
new_child_flag = True
check_doc_permissions(parent, 'create')
@@ -1312,7 +1317,7 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, chil
qty_unchanged = prev_qty == new_qty
uom_unchanged = prev_uom == new_uom
conversion_factor_unchanged = prev_con_fac == new_con_fac
date_unchanged = prev_date == new_date if prev_date and new_date else False # in case of delivery note etc
date_unchanged = prev_date == getdate(new_date) if prev_date and new_date else False # in case of delivery note etc
if rate_unchanged and qty_unchanged and conversion_factor_unchanged and uom_unchanged and date_unchanged:
continue

View File

@@ -6,6 +6,7 @@ import frappe
from frappe import _, msgprint
from frappe.utils import flt,cint, cstr, getdate
from six import iteritems
from collections import OrderedDict
from erpnext.accounts.party import get_party_details
from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
@@ -294,6 +295,9 @@ class BuyingController(StockController):
for raw_material in transferred_raw_materials + non_stock_items:
rm_item_key = (raw_material.rm_item_code, item.item_code, item.purchase_order)
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
if not raw_material_data and raw_material.get('batch_nos'):
backflushed_raw_materials_map.setdefault(rm_item_key, {'consumed_batch': {}})
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
consumed_qty = raw_material_data.get('qty', 0)
consumed_serial_nos = raw_material_data.get('serial_no', '')
@@ -325,14 +329,17 @@ class BuyingController(StockController):
batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code,
qty, transferred_batch_qty_map, backflushed_batch_qty_map, item.purchase_order)
for batch_data in batches_qty:
qty = batch_data['qty']
raw_material.batch_no = batch_data['batch']
self.append_raw_material_to_be_backflushed(item, raw_material, qty)
if qty > 0:
self.append_raw_material_to_be_backflushed(item, raw_material, qty)
else:
self.append_raw_material_to_be_backflushed(item, raw_material, qty)
def append_raw_material_to_be_backflushed(self, fg_item_doc, raw_material_data, qty):
qty = flt(qty, fg_item_doc.precision('qty'))
rm = self.append('supplied_items', {})
rm.update(raw_material_data)
@@ -790,9 +797,10 @@ class BuyingController(StockController):
if not self.get("items"):
return
earliest_schedule_date = min([d.schedule_date for d in self.get("items")])
if earliest_schedule_date:
self.schedule_date = earliest_schedule_date
if any(d.schedule_date for d in self.get("items")):
# Select earliest schedule_date.
self.schedule_date = min(d.schedule_date for d in self.get("items")
if d.schedule_date is not None)
if self.schedule_date:
for d in self.get('items'):
@@ -973,8 +981,16 @@ def get_non_stock_items(purchase_order, fg_item_code):
def set_serial_nos(raw_material, consumed_serial_nos, qty):
serial_nos = set(get_serial_nos(raw_material.serial_nos)) - \
set(get_serial_nos(consumed_serial_nos))
consumed_serial_nos_list = []
if consumed_serial_nos and isinstance(consumed_serial_nos, list):
for row in consumed_serial_nos:
consumed_serial_nos_list.extend(get_serial_nos(row))
elif consumed_serial_nos:
consumed_serial_nos_list = get_serial_nos(consumed_serial_nos)
serial_nos = set(get_serial_nos(raw_material.serial_nos)) - set(consumed_serial_nos_list)
if serial_nos and qty <= len(serial_nos):
raw_material.serial_no = '\n'.join(list(serial_nos)[0:frappe.utils.cint(qty)])
@@ -1009,7 +1025,7 @@ def get_transferred_batch_qty_map(purchase_order, fg_item):
for batch_data in transferred_batches:
key = ((batch_data.item_code, fg_item)
if batch_data.subcontracted_item else (batch_data.item_code, purchase_order))
transferred_batch_qty_map.setdefault(key, {})
transferred_batch_qty_map.setdefault(key, OrderedDict())
transferred_batch_qty_map[key][batch_data.batch_no] = batch_data.qty
return transferred_batch_qty_map
@@ -1062,8 +1078,14 @@ def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty
if available_qty >= required_qty:
available_batches.append({'batch': batch, 'qty': required_qty})
break
else:
elif available_qty != 0:
available_batches.append({'batch': batch, 'qty': available_qty})
required_qty -= available_qty
for row in available_batches:
if backflushed_batches.get(row.get('batch'), 0) > 0:
backflushed_batches[row.get('batch')] += row.get('qty')
else:
backflushed_batches.setdefault(row.get('batch'), row.get('qty'))
return available_batches

View File

@@ -320,7 +320,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
and status not in ("Stopped", "Closed") %(fcond)s
and (
(`tabDelivery Note`.is_return = 0 and `tabDelivery Note`.per_billed < 100)
or `tabDelivery Note`.grand_total = 0
or (`tabDelivery Note`.grand_total = 0 and `tabDelivery Note`.per_billed < 100)
or (
`tabDelivery Note`.is_return = 1
and return_against in (select name from `tabDelivery Note` where per_billed < 100)

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, comma_or, nowdate, getdate
from frappe.utils import flt, comma_or, nowdate, getdate, now
from frappe import _
from frappe.model.document import Document
@@ -307,10 +307,14 @@ class StatusUpdater(Document):
target.notify_update()
def _update_modified(self, args, update_modified):
args['update_modified'] = ''
if update_modified:
args['update_modified'] = ', modified = now(), modified_by = {0}'\
.format(frappe.db.escape(frappe.session.user))
if not update_modified:
args['update_modified'] = ''
return
args['update_modified'] = ', modified = {0}, modified_by = {1}'.format(
frappe.db.escape(now()),
frappe.db.escape(frappe.session.user)
)
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
ref_fieldname = frappe.scrub(ref_dt)

View File

@@ -418,7 +418,7 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle):
for e in existing_gle:
if entry.account == e.account:
account_existed = True
if entry.account == e.account and entry.against_account == e.against_account \
if entry.account == e.account \
and (not entry.cost_center or not e.cost_center or entry.cost_center == e.cost_center) \
and (entry.debit != e.debit or entry.credit != e.credit):
matched = False

View File

@@ -93,7 +93,7 @@
"fieldtype": "Column Break"
}
],
"modified": "2019-10-14 15:23:54.630731",
"modified": "2021-06-28 16:27:53.235714",
"modified_by": "Administrator",
"module": "CRM",
"name": "Appointment",
@@ -144,6 +144,18 @@
"role": "Sales User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Employee",
"share": 1,
"write": 1
}
],
"quick_entry": 1,

View File

@@ -277,7 +277,6 @@
"read_only": 1
},
{
"depends_on": "eval:",
"fieldname": "territory",
"fieldtype": "Link",
"label": "Territory",
@@ -413,7 +412,7 @@
],
"icon": "fa fa-info-sign",
"idx": 195,
"modified": "2020-08-12 23:34:39.665513",
"modified": "2021-06-04 10:11:22.831139",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunity",

View File

@@ -244,7 +244,6 @@ def make_quotation(source_name, target_doc=None):
"doctype": "Quotation",
"field_map": {
"opportunity_from": "quotation_to",
"opportunity_type": "order_type",
"name": "enq_no",
}
},

View File

@@ -58,7 +58,6 @@ class Student(Document):
student_user.flags.ignore_permissions = True
student_user.add_roles("Student")
student_user.save()
update_password_link = student_user.reset_password()
def update_applicant_status(self):
"""Updates Student Applicant status to Admitted"""

View File

@@ -345,11 +345,11 @@ def get_or_create_course_enrollment(course, program):
student = get_current_student()
course_enrollment = get_enrollment("course", course, student.name)
if not course_enrollment:
program_enrollment = get_enrollment('program', program, student.name)
program_enrollment = get_enrollment('program', program.name, student.name)
if not program_enrollment:
frappe.throw(_("You are not enrolled in program {0}".format(program)))
return
return student.enroll_in_course(course_name=course, program_enrollment=get_enrollment('program', program, student.name))
return student.enroll_in_course(course_name=course, program_enrollment=get_enrollment('program', program.name, student.name))
else:
return frappe.get_doc('Course Enrollment', course_enrollment)

View File

@@ -14,8 +14,7 @@ def verify_request():
)
if frappe.request.data and \
frappe.get_request_header("X-Wc-Webhook-Signature") and \
not sig == bytes(frappe.get_request_header("X-Wc-Webhook-Signature").encode()):
not sig == frappe.get_request_header("X-Wc-Webhook-Signature", "").encode():
frappe.throw(_("Unverified Webhook Data"))
frappe.set_user(woocommerce_settings.creation_user)

View File

@@ -117,7 +117,7 @@ def call_mws_method(mws_method, *args, **kwargs):
return response
except Exception as e:
delay = math.pow(4, x) * 125
frappe.log_error(message=e, title=str(mws_method))
frappe.log_error(message=e, title="Method {} failed".format(mws_method.__name__))
time.sleep(delay)
continue

View File

@@ -99,5 +99,7 @@ class PlaidConnector():
response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
transactions.extend(response["transactions"])
return transactions
except ItemError as e:
raise e
except Exception:
frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))

View File

@@ -15,6 +15,10 @@ frappe.ui.form.on('Plaid Settings', {
frm.add_custom_button(__('Link a new bank account'), () => {
new erpnext.integrations.plaidLink(frm);
});
frm.add_custom_button(__('Reset Plaid Link'), () => {
new erpnext.integrations.plaidLink(frm);
});
}
}
});

View File

@@ -1,5 +1,4 @@
{
"actions": [],
"creation": "2018-10-25 10:02:48.656165",
"doctype": "DocType",
"editable_grid": 1,
@@ -69,8 +68,7 @@
}
],
"issingle": 1,
"links": [],
"modified": "2020-10-29 20:24:56.916104",
"modified": "2021-03-02 18:05:50.794105",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Plaid Settings",
@@ -88,5 +86,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -12,6 +12,7 @@ from frappe.desk.doctype.tag.tag import add_tag
from frappe.model.document import Document
from frappe.utils import add_months, formatdate, getdate, today
from plaid.errors import ItemError
class PlaidSettings(Document):
@staticmethod
@@ -50,7 +51,7 @@ def add_institution(token, response):
})
bank.insert()
except Exception:
frappe.throw(frappe.get_traceback())
frappe.log_error(frappe.get_traceback(), title=_('Plaid Link Error'))
else:
bank = frappe.get_doc("Bank", response["institution"]["name"])
bank.plaid_access_token = access_token
@@ -82,7 +83,10 @@ def add_bank_accounts(response, bank, company):
if not acc_subtype:
add_account_subtype(account["subtype"])
if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])):
bank_account_name = "{} - {}".format(account["name"], bank["bank_name"])
existing_bank_account = frappe.db.exists("Bank Account", bank_account_name)
if not existing_bank_account:
try:
new_account = frappe.get_doc({
"doctype": "Bank Account",
@@ -102,10 +106,27 @@ def add_bank_accounts(response, bank, company):
except frappe.UniqueValidationError:
frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
except Exception:
frappe.throw(frappe.get_traceback())
frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
frappe.throw(_("There was an error creating Bank Account while linking with Plaid."),
title=_("Plaid Link Failed"))
else:
result.append(frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name"))
try:
existing_account = frappe.get_doc('Bank Account', existing_bank_account)
existing_account.update({
"bank": bank["bank_name"],
"account_name": account["name"],
"account_type": account.get("type", ""),
"account_subtype": account.get("subtype", ""),
"mask": account.get("mask", ""),
"integration_id": account["id"]
})
existing_account.save()
result.append(existing_bank_account)
except Exception:
frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
frappe.throw(_("There was an error updating Bank Account {} while linking with Plaid.").format(
existing_bank_account), title=_("Plaid Link Failed"))
return result
@@ -146,8 +167,9 @@ def sync_transactions(bank, bank_account):
transactions = get_transactions(bank=bank, bank_account=bank_account, start_date=start_date, end_date=end_date)
result = []
for transaction in reversed(transactions):
result += new_bank_transaction(transaction)
if transactions:
for transaction in reversed(transactions):
result += new_bank_transaction(transaction)
if result:
last_transaction_date = frappe.db.get_value('Bank Transaction', result.pop(), 'date')
@@ -173,7 +195,15 @@ def get_transactions(bank, bank_account=None, start_date=None, end_date=None):
account_id = None
plaid = PlaidConnector(access_token)
transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
transactions = []
try:
transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
except ItemError as e:
if e.code == "ITEM_LOGIN_REQUIRED":
msg = _("There was an error syncing transactions.") + " "
msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " "
frappe.log_error(msg, title=_("Plaid Link Refresh Required"))
return transactions
@@ -196,7 +226,7 @@ def new_bank_transaction(transaction):
try:
tags += transaction["category"]
tags += ["Plaid Cat. {}".format(transaction["category_id"])]
except KeyError:
except (KeyError, TypeError):
pass
if not frappe.db.exists("Bank Transaction", dict(transaction_id=transaction["transaction_id"])):
@@ -243,4 +273,4 @@ def automatic_synchronization():
@frappe.whitelist()
def get_link_token_for_update(access_token):
plaid = PlaidConnector(access_token)
return plaid.get_link_token(update_mode=True)
return plaid.get_link_token(update_mode=True)

View File

@@ -18,5 +18,8 @@ frappe.ui.form.on('Shopify Log', {
})
}).addClass('btn-primary');
}
let app_link = "<a href='https://frappecloud.com/marketplace/apps/ecommerce-integrations' target='_blank'>Ecommerce Integrations</a>"
frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true);
}
});

View File

@@ -64,5 +64,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

@@ -36,6 +36,10 @@ frappe.ui.form.on("Shopify Settings", "refresh", function(frm){
frm.toggle_reqd("delivery_note_series", frm.doc.sync_delivery_note);
}
let app_link = "<a href='https://frappecloud.com/marketplace/apps/ecommerce-integrations' target='_blank'>Ecommerce Integrations</a>"
frm.dashboard.add_comment(__("Shopify Integration will be removed from ERPNext in Version 14. Please install {0} app to continue using it.", [app_link]), "yellow", true);
})
$.extend(erpnext_integrations.shopify_settings, {

View File

@@ -2,6 +2,7 @@
"creation": "2015-05-18 05:21:07.270859",
"doctype": "DocType",
"document_type": "System",
"engine": "InnoDB",
"field_order": [
"status_html",
"enable_shopify",
@@ -258,8 +259,8 @@
}
],
"issingle": 1,
"modified": "2020-05-28 12:32:11.384757",
"modified_by": "umair@erpnext.com",
"modified": "2021-03-02 18:06:00.868688",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Shopify Settings",
"owner": "Administrator",
@@ -276,5 +277,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
}
"sort_order": "DESC",
"track_changes": 1
}

View File

@@ -30,7 +30,7 @@ class ShopifySettings(Document):
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
# url = get_shopify_url('admin/webhooks.json', self)
created_webhooks = [d.method for d in self.webhooks]
url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
url = get_shopify_url('admin/api/2021-04/webhooks.json', self)
for method in webhooks:
session = get_request_session()
try:
@@ -56,7 +56,7 @@ class ShopifySettings(Document):
deleted_webhooks = []
for d in self.webhooks:
url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
url = get_shopify_url('admin/api/2021-04/webhooks/{0}.json'.format(d.webhook_id), self)
try:
res = session.delete(url, headers=get_header(self))
res.raise_for_status()

View File

@@ -32,10 +32,12 @@ def create_customer(shopify_customer, shopify_settings):
raise e
def create_customer_address(customer, shopify_customer):
if not shopify_customer.get("addresses"):
return
addresses = shopify_customer.get("addresses", [])
for i, address in enumerate(shopify_customer.get("addresses")):
if not addresses and "default_address" in shopify_customer:
addresses.append(shopify_customer["default_address"])
for i, address in enumerate(addresses):
address_title, address_type = get_address_title_and_type(customer.customer_name, i)
try :
frappe.get_doc({

View File

@@ -8,7 +8,7 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo
shopify_variants_attr_list = ["option1", "option2", "option3"]
def sync_item_from_shopify(shopify_settings, item):
url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
url = get_shopify_url("admin/api/2021-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
session = get_request_session()
try:

View File

@@ -17,8 +17,7 @@ class ShopifySettings(unittest.TestCase):
frappe.set_user("Administrator")
# use the fixture data
import_doc(path=frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json"),
ignore_links=True, overwrite=True)
import_doc(path=frappe.get_app_path("erpnext", "erpnext_integrations/doctype/shopify_settings/test_data/custom_field.json"))
frappe.reload_doctype("Customer")
frappe.reload_doctype("Sales Order")

View File

@@ -18,7 +18,6 @@ def validate_webhooks_request(doctype, hmac_key, secret_key='secret'):
)
if frappe.request.data and \
frappe.get_request_header(hmac_key) and \
not sig == bytes(frappe.get_request_header(hmac_key).encode()):
frappe.throw(_("Unverified Webhook Data"))
frappe.set_user(settings.modified_by)

View File

@@ -246,7 +246,7 @@ doc_events = {
"on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
"on_trash": "erpnext.regional.check_deletion_permission",
"validate": "erpnext.regional.india.utils.set_transporter_address"
"validate": ["erpnext.regional.india.utils.set_transporter_address", "erpnext.regional.india.utils.update_taxable_values", "erpnext.regional.india.utils.validate_document_name"]
},
"Purchase Invoice": {
"validate": "erpnext.regional.india.utils.update_grand_total_for_rcm"

View File

@@ -78,7 +78,7 @@
"search_index": 1
},
{
"depends_on": "eval:doc.status==\"On Leave\"",
"depends_on": "eval:doc.status==\"On Leave\" || doc.status==\"Half Day\"",
"fieldname": "leave_type",
"fieldtype": "Link",
"in_standard_filter": 1,
@@ -174,7 +174,7 @@
"icon": "fa fa-ok",
"idx": 1,
"is_submittable": 1,
"modified": "2020-02-19 14:25:32.945842",
"modified": "2021-06-30 14:42:39.162146",
"modified_by": "Administrator",
"module": "HR",
"name": "Attendance",

View File

@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import date_diff, add_days, getdate, cint
from frappe.utils import date_diff, add_days, getdate, cint, formatdate as format_date
from frappe.model.document import Document
from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, \
get_holidays_for_employee, create_additional_leave_ledger_entry
@@ -40,7 +40,12 @@ class CompensatoryLeaveRequest(Document):
def validate_holidays(self):
holidays = get_holidays_for_employee(self.employee, self.work_from_date, self.work_end_date)
if len(holidays) < date_diff(self.work_end_date, self.work_from_date) + 1:
frappe.throw(_("Compensatory leave request days not in valid holidays"))
if date_diff(self.work_end_date, self.work_from_date):
msg = _("The days between {0} to {1} are not valid holidays.").format(frappe.bold(format_date(self.work_from_date)), frappe.bold(format_date(self.work_end_date)))
else:
msg = _("{0} is not a holiday.").format(frappe.bold(format_date(self.work_from_date)))
frappe.throw(msg)
def on_submit(self):
company = frappe.db.get_value("Employee", self.employee, "company")
@@ -63,7 +68,7 @@ class CompensatoryLeaveRequest(Document):
leave_allocation = self.create_leave_allocation(leave_period, date_difference)
self.leave_allocation=leave_allocation.name
else:
frappe.throw(_("There is no leave period in between {0} and {1}").format(self.work_from_date, self.work_end_date))
frappe.throw(_("There is no leave period in between {0} and {1}").format(format_date(self.work_from_date), format_date(self.work_end_date)))
def on_cancel(self):
if self.leave_allocation:

View File

@@ -57,6 +57,9 @@ class Employee(NestedSet):
remove_user_permission(
"Employee", self.name, existing_user_id)
def after_rename(self, old, new, merge):
self.db_set("employee", new)
def set_employee_name(self):
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))

View File

@@ -1,626 +1,177 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "HR-EMP-SEP-.YYYY.-.#####",
"beta": 0,
"creation": "2018-05-10 02:29:16.740490",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"actions": [],
"autoname": "HR-EMP-SEP-.YYYY.-.#####",
"creation": "2018-05-10 02:29:16.740490",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"employee",
"employee_name",
"department",
"designation",
"employee_grade",
"column_break_7",
"company",
"boarding_status",
"resignation_letter_date",
"project",
"table_for_activity",
"employee_separation_template",
"activities",
"notify_users_by_email",
"section_break_14",
"exit_interview",
"amended_from"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee",
"length": 0,
"no_copy": 0,
"options": "Employee",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Employee Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.resignation_letter_date",
"fieldname": "resignation_letter_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Resignation Letter Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "boarding_status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "\nPending\nIn Process\nCompleted",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fieldname": "employee",
"fieldtype": "Link",
"label": "Employee",
"options": "Employee",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_in_quick_entry": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_users_by_email",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notify users by email",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_7",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "employee_separation_template",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee Separation Template",
"length": 0,
"no_copy": 0,
"options": "Employee Separation Template",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.company",
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fetch_from": "employee.employee_name",
"fieldname": "employee_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Employee Name",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "project",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Project",
"length": 0,
"no_copy": 0,
"options": "Project",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fetch_from": "employee.resignation_letter_date",
"fieldname": "resignation_letter_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Resignation Letter Date",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Department",
"length": 0,
"no_copy": 0,
"options": "Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"allow_on_submit": 1,
"fieldname": "boarding_status",
"fieldtype": "Select",
"label": "Status",
"options": "\nPending\nIn Process\nCompleted",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.designation",
"fieldname": "designation",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Designation",
"length": 0,
"no_copy": 0,
"options": "Designation",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"allow_on_submit": 1,
"default": "0",
"fieldname": "notify_users_by_email",
"fieldtype": "Check",
"label": "Notify users by email"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.grade",
"fieldname": "employee_grade",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Employee Grade",
"length": 0,
"no_copy": 0,
"options": "Employee Grade",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "column_break_7",
"fieldtype": "Column Break"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "table_for_activity",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "employee_separation_template",
"fieldtype": "Link",
"label": "Employee Separation Template",
"options": "Employee Separation Template"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "activities",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Activities",
"length": 0,
"no_copy": 0,
"options": "Employee Boarding Activity",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fetch_from": "employee.company",
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"reqd": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
"options": "Project",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "exit_interview",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Exit Interview Summary",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
"fetch_from": "employee.department",
"fieldname": "department",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Department",
"options": "Department",
"read_only": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amended From",
"length": 0,
"no_copy": 1,
"options": "Employee Separation",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"fetch_from": "employee.designation",
"fieldname": "designation",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Designation",
"options": "Designation",
"read_only": 1
},
{
"fetch_from": "employee.grade",
"fieldname": "employee_grade",
"fieldtype": "Link",
"label": "Employee Grade",
"options": "Employee Grade",
"read_only": 1
},
{
"fieldname": "table_for_activity",
"fieldtype": "Section Break",
"label": "Separation Activities"
},
{
"allow_on_submit": 1,
"fieldname": "activities",
"fieldtype": "Table",
"label": "Activities",
"options": "Employee Boarding Activity"
},
{
"fieldname": "section_break_14",
"fieldtype": "Section Break"
},
{
"fieldname": "exit_interview",
"fieldtype": "Text Editor",
"label": "Exit Interview Summary"
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Employee Separation",
"print_hide": 1,
"read_only": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-08-03 16:15:39.025898",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Separation",
"name_case": "",
"owner": "Administrator",
],
"is_submittable": 1,
"links": [],
"modified": "2021-04-28 15:58:36.020196",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Separation",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"amend": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "employee_name",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "employee_name",
"track_changes": 1
}

View File

@@ -18,7 +18,7 @@ class TestEmployeeSeparation(unittest.TestCase):
'activity_name': 'Deactivate Employee',
'role': 'HR User'
})
separation.status = 'Pending'
separation.boarding_status = 'Pending'
separation.insert()
separation.submit()
self.assertEqual(separation.docstatus, 1)

View File

@@ -175,7 +175,7 @@
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2019-12-31 14:28:32.004121",
"modified": "2021-02-25 13:06:37.978785",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
@@ -192,5 +192,6 @@
}
],
"sort_field": "modified",
"sort_order": "ASC"
"sort_order": "ASC",
"track_changes": 1
}

View File

@@ -2,7 +2,7 @@
// MIT License. See license.txt
frappe.listview_settings['Job Applicant'] = {
add_fields: ["company", "designation", "job_applicant", "status"],
add_fields: ["status"],
get_indicator: function (doc) {
if (doc.status == "Accepted") {
return [__(doc.status), "green", "status,=," + doc.status];

View File

@@ -5,8 +5,8 @@
frappe.ui.form.on('Loan Application', {
refresh: function(frm) {
frm.trigger("toggle_fields")
frm.trigger("add_toolbar_buttons")
frm.trigger("toggle_fields");
frm.trigger("add_toolbar_buttons");
},
repayment_method: function(frm) {
frm.doc.repayment_amount = frm.doc.repayment_periods = ""

View File

@@ -5,6 +5,7 @@ frappe.ui.form.on('Salary Component', {
setup: function(frm) {
frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
return {
filters: {
"is_group": 0,

View File

@@ -303,11 +303,11 @@ class SalarySlip(TransactionBase):
if self.salary_structure:
self.calculate_component_amounts("deductions")
self.set_loan_repayment()
self.set_component_amounts_based_on_payment_days()
self.set_net_pay()
def set_net_pay(self):
self.total_deduction = self.get_component_totals("deductions")
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
@@ -519,7 +519,7 @@ class SalarySlip(TransactionBase):
# Total taxable earnings including additional and other incomes
total_taxable_earnings = previous_taxable_earnings + current_structured_taxable_earnings + future_structured_taxable_earnings \
+ current_additional_earnings + other_incomes + unclaimed_taxable_benefits - total_exemption_amount
# Total taxable earnings without additional earnings with full tax
total_taxable_earnings_without_full_tax_addl_components = total_taxable_earnings - current_additional_earnings_with_full_tax
@@ -527,7 +527,7 @@ class SalarySlip(TransactionBase):
total_structured_tax_amount = self.calculate_tax_by_tax_slab(
total_taxable_earnings_without_full_tax_addl_components, tax_slab)
current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
# Total taxable earnings with additional earnings with full tax
full_tax_on_additional_earnings = 0.0
if current_additional_earnings_with_full_tax:
@@ -563,7 +563,7 @@ class SalarySlip(TransactionBase):
select sum(sd.amount)
from
`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
where
where
sd.parentfield='earnings'
and sd.is_tax_applicable=1
and is_flexible_benefit=0
@@ -676,9 +676,11 @@ class SalarySlip(TransactionBase):
def get_amount_based_on_payment_days(self, row, joining_date, relieving_date):
amount, additional_amount = row.amount, row.additional_amount
timesheet_component = frappe.db.get_value("Salary Structure", self.salary_structure, "salary_component")
if (self.salary_structure and
cint(row.depends_on_payment_days) and cint(self.total_working_days) and
(not self.salary_slip_based_on_timesheet or
cint(row.depends_on_payment_days) and cint(self.total_working_days)
and (row.salary_component != timesheet_component or
getdate(self.start_date) < joining_date or
(relieving_date and getdate(self.end_date) > relieving_date)
)):
@@ -687,14 +689,14 @@ class SalarySlip(TransactionBase):
amount = flt((flt(row.default_amount) * flt(self.payment_days)
/ cint(self.total_working_days)), row.precision("amount")) + additional_amount
elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(row.depends_on_payment_days):
elif not self.payment_days and row.salary_component != timesheet_component and cint(row.depends_on_payment_days):
amount, additional_amount = 0, 0
elif not row.amount:
amount = flt(row.default_amount) + flt(row.additional_amount)
# apply rounding
if frappe.get_cached_value("Salary Component", row.salary_component, "round_to_the_nearest_integer"):
amount, additional_amount = rounded(amount), rounded(additional_amount)
amount, additional_amount = rounded(amount or 0), rounded(additional_amount or 0)
return amount, additional_amount
@@ -782,7 +784,7 @@ class SalarySlip(TransactionBase):
if flt(d.max_taxable_income) and flt(d.max_taxable_income) < annual_taxable_earning:
continue
tax_amount += tax_amount * flt(d.percent) / 100
return tax_amount
@@ -869,8 +871,8 @@ class SalarySlip(TransactionBase):
`tabRepayment Schedule` as rps, `tabLoan` as l
where
l.name = rps.parent and rps.payment_date between %s and %s and
l.repay_from_salary = 1 and l.docstatus = 1 and l.applicant = %s""",
(self.start_date, self.end_date, self.employee), as_dict=True) or []
l.repay_from_salary = 1 and l.docstatus = 1 and l.applicant = %s and l.company = %s""",
(self.start_date, self.end_date, self.employee, self.company), as_dict=True) or []
def update_salary_slip_in_additional_salary(self):
salary_slip = self.name if self.docstatus==1 else None

View File

@@ -115,6 +115,41 @@ class TestSalarySlip(unittest.TestCase):
frappe.db.set_value("Employee", frappe.get_value("Employee",
{"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
def test_payment_days_in_salary_slip_based_on_timesheet(self):
from erpnext.projects.doctype.timesheet.test_timesheet import (
make_salary_structure_for_timesheet,
make_timesheet,
)
from erpnext.projects.doctype.timesheet.timesheet import (
make_salary_slip as make_salary_slip_for_timesheet,
)
# Holidays included in working days
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
emp = make_employee("test_employee_timesheet1@salary.com", company=erpnext.get_default_company())
frappe.db.set_value("Employee", emp, {"relieving_date": None, "status": "Active"})
# salary structure based on timesheet
make_salary_structure_for_timesheet(emp)
timesheet = make_timesheet(emp, simulate=True)
salary_slip = make_salary_slip_for_timesheet(timesheet.name)
salary_slip.start_date = get_first_day(nowdate())
salary_slip.end_date = get_last_day(nowdate())
salary_slip.save()
salary_slip.submit()
no_of_days = self.get_no_of_days()
days_in_month = no_of_days[0]
no_of_holidays = no_of_days[1]
self.assertEqual(salary_slip.payment_days, days_in_month - no_of_holidays)
# gross pay calculation based on attendance (payment days)
gross_pay = 78100 - ((78000 / (days_in_month - no_of_holidays)) * flt(salary_slip.leave_without_pay))
self.assertEqual(salary_slip.gross_pay, flt(gross_pay, 2))
def test_employee_salary_slip_read_permission(self):
make_employee("test_employee@salary.com")
@@ -175,7 +210,7 @@ class TestSalarySlip(unittest.TestCase):
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""")
payroll_period = create_payroll_period()
create_tax_slab(payroll_period, allow_tax_exemption=True)

View File

@@ -40,7 +40,7 @@ class StaffingPlan(Document):
detail.current_openings = designation_counts['job_openings']
if detail.number_of_positions > 0:
if detail.vacancies > 0 and detail.estimated_cost_per_position:
if detail.vacancies and detail.estimated_cost_per_position:
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
self.total_estimated_budget += detail.total_estimated_cost
@@ -57,8 +57,7 @@ class StaffingPlan(Document):
and sp.to_date >= %s and sp.from_date <= %s and sp.company = %s
""", (staffing_plan_detail.designation, self.from_date, self.to_date, self.company))
if overlap and overlap [0][0]:
frappe.throw(_("Staffing Plan {0} already exist for designation {1}"
.format(overlap[0][0], staffing_plan_detail.designation)))
frappe.throw(_("Staffing Plan {0} already exist for designation {1}").format(overlap[0][0], staffing_plan_detail.designation))
def validate_with_parent_plan(self, staffing_plan_detail):
if not frappe.get_cached_value('Company', self.company, "parent_company"):
@@ -75,12 +74,12 @@ class StaffingPlan(Document):
if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
for {2} as per staffing plan {3} for parent company {4}."
.format(cint(parent_plan_details[0].vacancies),
for {2} as per staffing plan {3} for parent company {4}.").format(
cint(parent_plan_details[0].vacancies),
parent_plan_details[0].total_estimated_cost,
frappe.bold(staffing_plan_detail.designation),
parent_plan_details[0].name,
parent_company)), ParentCompanyError)
parent_company), ParentCompanyError)
#Get vacanices already planned for all companies down the hierarchy of Parent Company
lft, rgt = frappe.get_cached_value('Company', parent_company, ["lft", "rgt"])
@@ -97,14 +96,14 @@ class StaffingPlan(Document):
(flt(parent_plan_details[0].total_estimated_cost) < \
(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}."
.format(cint(all_sibling_details.vacancies),
You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}.").format(
cint(all_sibling_details.vacancies),
all_sibling_details.total_estimated_cost,
frappe.bold(staffing_plan_detail.designation),
parent_company,
cint(parent_plan_details[0].vacancies),
parent_plan_details[0].total_estimated_cost,
parent_plan_details[0].name)))
parent_plan_details[0].name))
def validate_with_subsidiary_plans(self, staffing_plan_detail):
#Valdate this plan with all child company plan
@@ -120,11 +119,11 @@ class StaffingPlan(Document):
cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies"
.format(self.company,
Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies").format(
self.company,
cint(children_details.vacancies),
children_details.total_estimated_cost,
frappe.bold(staffing_plan_detail.designation))), SubsidiaryCompanyError)
frappe.bold(staffing_plan_detail.designation)), SubsidiaryCompanyError)
@frappe.whitelist()
def get_designation_counts(designation, company):

View File

@@ -89,6 +89,7 @@ def execute(filters=None):
"amount": salary.net_pay,
}
data.append(row)
return columns, data
def get_bank_accounts():
@@ -110,7 +111,7 @@ def get_payroll_entries(accounts, filters):
entries = get_all("Payroll Entry", payroll_filter, ["name", "payment_account"])
payment_accounts = [d.payment_account for d in entries]
set_company_account(payment_accounts, entries)
entries = set_company_account(payment_accounts, entries)
return entries
def get_salary_slips(payroll_entries):

View File

@@ -124,11 +124,12 @@ def get_allocated_and_expired_leaves(records, from_date, to_date):
def get_leave_ledger_entries(from_date, to_date, employee, leave_type):
records= frappe.db.sql("""
SELECT
employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type
is_carry_forward, is_expired
employee, leave_type, from_date, to_date, leaves, transaction_name,
transaction_type, is_carry_forward, is_expired
FROM `tabLeave Ledger Entry`
WHERE employee=%(employee)s AND leave_type=%(leave_type)s
AND docstatus=1
AND transaction_type = 'Leave Allocation'
AND (from_date between %(from_date)s AND %(to_date)s
OR to_date between %(from_date)s AND %(to_date)s
OR (from_date < %(from_date)s AND to_date > %(to_date)s))

View File

@@ -1,16 +1,19 @@
# 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, erpnext
from frappe import _
from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr, add_days, today
from frappe.model.document import Document
from frappe.desk.form import assign_to
import erpnext
import frappe
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from frappe import _
from frappe.desk.form import assign_to
from frappe.model.document import Document
from frappe.utils import (add_days, cstr, flt, format_datetime, formatdate,
get_datetime, getdate, nowdate, today, unique)
class DuplicateDeclarationError(frappe.ValidationError): pass
class EmployeeBoardingController(Document):
'''
Create the project and the task for the boarding process
@@ -29,13 +32,15 @@ class EmployeeBoardingController(Document):
project_name += self.job_applicant
else:
project_name += self.employee
project = frappe.get_doc({
"doctype": "Project",
"project_name": project_name,
"expected_start_date": self.date_of_joining if self.doctype == "Employee Onboarding" else self.resignation_letter_date,
"department": self.department,
"company": self.company
}).insert(ignore_permissions=True)
}).insert(ignore_permissions=True, ignore_mandatory=True)
self.db_set("project", project.name)
self.db_set("boarding_status", "Pending")
self.reload()
@@ -48,27 +53,38 @@ class EmployeeBoardingController(Document):
continue
task = frappe.get_doc({
"doctype": "Task",
"project": self.project,
"subject": activity.activity_name + " : " + self.employee_name,
"description": activity.description,
"department": self.department,
"company": self.company,
"task_weight": activity.task_weight
}).insert(ignore_permissions=True)
"doctype": "Task",
"project": self.project,
"subject": activity.activity_name + " : " + self.employee_name,
"description": activity.description,
"department": self.department,
"company": self.company,
"task_weight": activity.task_weight
}).insert(ignore_permissions=True)
activity.db_set("task", task.name)
users = [activity.user] if activity.user else []
if activity.role:
user_list = frappe.db.sql_list('''select distinct(parent) from `tabHas Role`
where parenttype='User' and role=%s''', activity.role)
users = users + user_list
user_list = frappe.db.sql_list('''
SELECT
DISTINCT(has_role.parent)
FROM
`tabHas Role` has_role
LEFT JOIN `tabUser` user
ON has_role.parent = user.name
WHERE
has_role.parenttype = 'User'
AND user.enabled = 1
AND has_role.role = %s
''', activity.role)
users = unique(users + user_list)
if "Administrator" in users:
users.remove("Administrator")
# assign the task the users
if users:
self.assign_task_to_users(task, set(users))
self.assign_task_to_users(task, users)
def assign_task_to_users(self, task, users):
for user in users:
@@ -122,6 +138,8 @@ def update_employee(employee, details, date=None, cancel=False):
new_data = getdate(new_data)
elif fieldtype =="Datetime" and new_data:
new_data = get_datetime(new_data)
elif fieldtype in ["Currency", "Float"] and new_data:
new_data = flt(new_data)
setattr(employee, item.fieldname, new_data)
if item.fieldname in ["department", "designation", "branch"]:
internal_work_history[item.fieldname] = item.new
@@ -453,4 +471,4 @@ def get_previous_claimed_amount(employee, payroll_period, non_pro_rata=False, co
}, as_dict=True)
if sum_of_claimed_amount and flt(sum_of_claimed_amount[0].total_amount) > 0:
total_claimed_amount = sum_of_claimed_amount[0].total_amount
return total_claimed_amount
return total_claimed_amount

View File

@@ -27,6 +27,9 @@ frappe.ui.form.on('Maintenance Visit', {
if (frm.doc.__islocal) {
frm.set_value({mntc_date: frappe.datetime.get_today()});
}
if (frm.doc.purposes.length && frm.doc.purposes[0].item_name == undefined) {
frm.clear_table("purposes");
}
},
customer: function(frm) {
erpnext.utils.get_party_details(frm);
@@ -49,13 +52,17 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
if (this.frm.doc.docstatus===0) {
this.frm.add_custom_button(__('Maintenance Schedule'),
function() {
function () {
if (!me.frm.doc.customer) {
frappe.msgprint(__('Please select Customer first'));
return;
}
erpnext.utils.map_current_doc({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
source_doctype: "Maintenance Schedule",
target: me.frm,
setters: {
customer: me.frm.doc.customer || undefined,
customer: me.frm.doc.customer,
},
get_query_filters: {
docstatus: 1,
@@ -80,13 +87,17 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
})
}, __("Get items from"));
this.frm.add_custom_button(__('Sales Order'),
function() {
function () {
if (!me.frm.doc.customer) {
frappe.msgprint(__('Please select Customer first'));
return;
}
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
source_doctype: "Sales Order",
target: me.frm,
setters: {
customer: me.frm.doc.customer || undefined,
customer: me.frm.doc.customer,
},
get_query_filters: {
docstatus: 1,
@@ -99,4 +110,4 @@ erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
},
});
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));

View File

@@ -240,6 +240,9 @@ class BOM(WebsiteGenerator):
existing_bom_cost = self.total_cost
for d in self.get("items"):
if not d.item_code:
continue
rate = self.get_rm_rate({
"company": self.company,
"item_code": d.item_code,
@@ -414,25 +417,29 @@ class BOM(WebsiteGenerator):
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
def check_recursion(self, bom_list=[]):
def check_recursion(self, bom_list=None):
""" Check whether recursion occurs in any bom"""
def _throw_error(bom_name):
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {0}").format(bom_name))
bom_list = self.traverse_tree()
bom_nos = frappe.get_all('BOM Item', fields=["bom_no"],
filters={'parent': ('in', bom_list), 'parenttype': 'BOM'})
child_items = frappe.get_all('BOM Item', fields=["bom_no", "item_code"],
filters={'parent': ('in', bom_list), 'parenttype': 'BOM'}) or []
raise_exception = False
if bom_nos and self.name in [d.bom_no for d in bom_nos]:
raise_exception = True
child_bom = {d.bom_no for d in child_items}
child_items_codes = {d.item_code for d in child_items}
if not raise_exception:
bom_nos = frappe.get_all('BOM Item', fields=["parent"],
filters={'bom_no': self.name, 'parenttype': 'BOM'})
if self.name in child_bom:
_throw_error(self.name)
if self.name in [d.parent for d in bom_nos]:
raise_exception = True
if self.item in child_items_codes:
_throw_error(self.item)
if raise_exception:
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
bom_nos = frappe.get_all('BOM Item', fields=["parent"],
filters={'bom_no': self.name, 'parenttype': 'BOM'}) or []
if self.name in {d.parent for d in bom_nos}:
_throw_error(self.name)
def update_cost_and_exploded_items(self, bom_list=[]):
bom_list = self.traverse_tree(bom_list)
@@ -545,7 +552,7 @@ class BOM(WebsiteGenerator):
for d in self.get('items'):
if d.bom_no:
self.get_child_exploded_items(d.bom_no, d.stock_qty)
else:
elif d.item_code:
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d.item_code,
'item_name' : d.item_name,

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