Compare commits

...

660 Commits

Author SHA1 Message Date
Saurabh
cdf8016bcd Merge branch 'hotfix' 2017-11-10 13:15:04 +05:30
Saurabh
18c8cf965f bumped to version 9.2.8 2017-11-10 13:45:04 +06:00
Nabin Hait
8e3da7f70e Update test_assessment_plan.js 2017-11-10 10:59:17 +05:30
Nabin Hait
887285ed1a Update test_assessment_plan.js 2017-11-10 10:59:07 +05:30
Manas Solanki
aeb0026354 commits from develop merged PR's (#11491)
* better student search queries and minor fixes in the student group

* remove the print option for the tools

* fixes for the chart

* minor fixes in the fee module for print and permission, delete redundant doctype

* set the naming series and independent dob validation
2017-11-10 10:58:43 +05:30
rohitwaghchaure
1ce48e7032 [fix] POS profile patch (#11501) 2017-11-10 10:53:12 +05:30
Faris Ansari
99e31f97b8 set default params for paging (#11500) 2017-11-10 10:50:49 +05:30
Faris Ansari
4a864c1eea [fix] Update bom item description (#11498)
* [fix] Update bom item description

* Update item.py
2017-11-09 19:01:21 +05:30
Prateeksha Singh
3e998bccba Merge pull request #11490 from pratu16x7/hotfix
[minor][hotfix] naming_series variable assignment
2017-11-08 17:22:49 +05:30
pratu16x7
40016372c6 [minor][hotfix] naming_series variable assignment 2017-11-08 16:30:15 +05:30
Saurabh
af22f84809 Merge branch 'hotfix' 2017-11-08 15:07:33 +05:30
Saurabh
3894a5ed94 bumped to version 9.2.7 2017-11-08 15:37:33 +06:00
Saurabh
045b2877b7 [fix] remove warehouse from Stock Settings if warehouse wont exists (#11487) 2017-11-08 14:57:03 +05:30
Saurabh
148b62a206 Merge pull request #11486 from saurabh6790/patch_fixes_
[fix] catch link validation exception in POS profile and reload fees …
2017-11-08 14:48:33 +05:30
Saurabh
d2cef208fe [fix] catch link validation exception in POS profile and reload fees doctype 2017-11-08 14:44:43 +05:30
Saurabh
4c617d6496 Merge branch 'staging' 2017-11-08 12:20:46 +05:30
Saurabh
f985ae1379 bumped to version 9.2.6 2017-11-08 12:50:46 +06:00
Saurabh
98aa544f25 Merge branch 'master' into staging 2017-11-08 12:18:50 +05:30
Saurabh
6ad1082433 Merge branch 'hotfix' 2017-11-08 12:12:37 +05:30
Saurabh
db781e607a bumped to version 9.2.5 2017-11-08 12:42:37 +06:00
rohitwaghchaure
521606e433 Merge pull request #11398 from rohitwaghchaure/item_variants_donot_copy_option
[enhance] In item variants settings added provision, do not update the variants of variants from the template but will copy the value while making new variant aginst the template
2017-11-08 11:49:24 +05:30
Rohit Waghchaure
acc8995c48 [enhance] In item variants settings added provision, do not update the fields of variants from the template but will copy the value while making new variant aginst the template 2017-11-08 11:39:08 +05:30
rohitwaghchaure
f688af3809 [fix] Offline pos name is not defined issue in the POS (#11469) 2017-11-08 11:33:39 +05:30
rohitwaghchaure
9f2a27c99c Merge pull request #11477 from rohitwaghchaure/pos_profile_test_cases
[fix] POS Profile test cases
2017-11-07 16:35:52 +05:30
rohitwaghchaure
6058dcc2ce Merge pull request #11470 from rohitwaghchaure/pos_online_invalid_grand_total_issue
[Fix] Fast clicking on an item, showing invalid grand total and quantity in the POS cart
2017-11-07 16:19:51 +05:30
Rohit Waghchaure
35fc45eff9 [fix] POS Profile test cases 2017-11-07 10:43:16 +05:30
Rohit Waghchaure
57cc924d29 [Fix] Fast clicking on an item, showing invalid grand total and quantity in the POS cart 2017-11-06 18:42:37 +05:30
rohitwaghchaure
adbbb0b0f3 Merge pull request #11364 from manassolanki/set-pos-profile
set the pos profile in the sales invoice
2017-11-06 14:08:59 +05:30
Manas Solanki
40ef7e7039 patch for renaming the pos profile and setting the pos profile name 2017-11-06 13:53:52 +05:30
Manas Solanki
b1616a0cb3 changes in thepos profile 2017-11-06 13:53:52 +05:30
Manas Solanki
3f0dfd720f set the pos profile in the sales invoice 2017-11-06 13:53:52 +05:30
Saurabh
e850655c1d Merge branch 'master' into staging 2017-11-03 16:56:24 +05:30
Saurabh
5647bf081a Merge branch 'hotfix' 2017-11-03 16:56:23 +05:30
Saurabh
56cb0aa9c1 bumped to version 9.2.4 2017-11-03 17:26:23 +06:00
rohitwaghchaure
7677ff00a2 [hotfix] User not able to edit exchange rate even if Allow Stale Exchange Rates is disabled in the accounts settings (#11409) 2017-11-02 18:12:14 +05:30
Saurabh
62fd4007b0 Merge branch 'master' into staging 2017-11-02 12:14:42 +05:30
Saurabh
75f3f81a9b Merge branch 'hotfix' 2017-11-02 12:14:41 +05:30
Saurabh
870ce3cfea bumped to version 9.2.3 2017-11-02 12:44:40 +06:00
Saurabh
0ad2cc3def Merge pull request #11403 from tundebabzy/issue-11402
Error In Employee Loan Form (#11402)
2017-11-02 12:09:54 +05:30
Saurabh
00f6c2d61d Merge pull request #11417 from rohitwaghchaure/issue_not_save_v9
[Fix] Customer is manadatory even if customer has selected in the Issue
2017-11-02 12:07:32 +05:30
Saurabh
38008f8daa Merge pull request #11406 from rohitwaghchaure/payment_entry_differnece_amount_issue
[Fix] Wrong difference amount in the payment entry for the internal transfer type
2017-11-02 12:07:14 +05:30
Saurabh
afb63af3b6 Merge pull request #11397 from rohitwaghchaure/delivery_note_issue_from_so
[Fix] Getting an error while making delivery note from sales order and sales order has no item code
2017-11-02 12:06:08 +05:30
Rohit Waghchaure
816ce33daf [Fix] Customer is manadatory even if customer has selected in the Issue 2017-11-01 19:02:09 +05:30
Rohit Waghchaure
99748dbacf [Fix] Wrong difference amount in the payment entry for the internal transfer type 2017-11-01 11:45:02 +05:30
tunde
31287b00a6 call get_employee_loan_application only when appropriate 2017-10-31 18:10:17 +01:00
Rohit Waghchaure
5ec9f6930b [Fix] Getting an error while making delivery note from sales order and sales order has no item code 2017-10-31 15:26:56 +05:30
Faris Ansari
40611e4f69 [fix] hub get_item_details (#11383) 2017-10-31 13:00:09 +05:30
Saurabh
dd0bdc7fa6 Merge pull request #11356 from tundebabzy/issue-11355
fix object has not attribute 'is_item_from_hub'
2017-10-31 12:23:09 +05:30
tunde
bbce7b7e5d get attribute with get method 2017-10-26 14:31:13 +01:00
Nabin Hait
c799a22d55 Merge branch 'master' into staging 2017-10-26 14:35:34 +05:30
Nabin Hait
92e09c0b7b Merge branch 'hotfix' 2017-10-26 14:35:33 +05:30
Nabin Hait
819c50c042 bumped to version 9.2.2 2017-10-26 15:05:33 +06:00
Faris Ansari
6887cedaea [fix] item qty trigger (#11349) 2017-10-26 14:34:15 +05:30
Nabin Hait
aa7896f1e1 [test] Fixed physician test cases (#11347) 2017-10-26 14:33:28 +05:30
Nabin Hait
52909b73bb [test] Fixed advance jv cancellation (#11333) 2017-10-26 11:06:07 +05:30
Saurabh
b445633e56 Merge branch 'master' into staging 2017-10-26 09:59:22 +05:30
Saurabh
5235aa833c Merge branch 'hotfix' 2017-10-26 09:59:22 +05:30
Saurabh
d0131762cc bumped to version 9.2.1 2017-10-26 10:29:22 +06:00
Saurabh
97b98b6c01 Merge pull request #11345 from saurabh6790/setup_wiz_fixes
[HOTFIX] translate domain
2017-10-26 09:52:45 +05:30
Saurabh
92a6155bb0 [fix] translate domain 2017-10-26 09:44:51 +05:30
Saurabh
d6e67ce123 [fix] check for null date fields (#11334) 2017-10-25 17:44:22 +05:30
Nabin Hait
6a4e230cde [fix] Status of Item (#11326) 2017-10-25 17:06:30 +05:30
rohitwaghchaure
c65f1d7745 Search item using name instead of item code (#11327) 2017-10-25 17:04:56 +05:30
rohitwaghchaure
e02ee898e9 [Fix] Production order not displaying in the calendar view, if po has no operations (#11328) 2017-10-25 17:04:31 +05:30
rohitwaghchaure
2e6f6d6749 [minor] cleanup code (#11331) 2017-10-25 17:03:49 +05:30
Nabin Hait
014b138074 Merge branch 'tundebabzy-issue-11080' into hotfix 2017-10-25 15:53:53 +05:30
Nabin Hait
fb734976eb Removed appintment field from Invoice, it should be a custom field and will be added from domain settings 2017-10-25 15:53:07 +05:30
Nabin Hait
6500af9aa2 Merge branch 'develop' into staging 2017-10-25 14:25:06 +05:30
Nabin Hait
8f2500083c Merge branch 'master' into develop 2017-10-25 14:10:39 +05:30
Nabin Hait
8e7ba95b78 Merge branch 'staging' 2017-10-25 14:10:38 +05:30
Nabin Hait
e146143bd1 bumped to version 9.2.0 2017-10-25 14:40:38 +06:00
Nabin Hait
4d22b6db30 Fixed Merge Conflict 2017-10-25 14:09:46 +05:30
Nabin Hait
cd3dbcb2ef Fixed Merge Conflict 2017-10-25 14:07:25 +05:30
Nabin Hait
bdfc074a7d Merge branch 'hotfix' 2017-10-25 14:02:33 +05:30
Nabin Hait
c7bd77111e bumped to version 9.1.8 2017-10-25 14:32:32 +06:00
rohitwaghchaure
4a60554b91 Green indicator in the cart for non stock item (#11325) 2017-10-25 13:59:29 +05:30
rohitwaghchaure
3dc21b099d [Fix] Translation issue (#11323) 2017-10-25 12:38:17 +05:30
tundebabzy
40a02769c5 Error in the Address fetched in Sales Order.(#11129) (#11145)
* add new function - `get_party_shipping_address`

* `swap `get_default_address` with `get_party_shipping_address`

* test cases

* properly sets order by direction

* move `get_party_shipping_address` to party.py

* fix test module import
2017-10-25 12:24:34 +05:30
tundebabzy
bafcd7418a Add Bundle Description Field To Product Bundle (#11122)
* add description field that shows in list view

* description field should be simply `description`
2017-10-25 12:22:08 +05:30
Makarand Bauskar
085b4842a1 [minor] minor fixes in get_company_details for Hub page (#11168) 2017-10-25 12:19:10 +05:30
Makarand Bauskar
e6712c129c [hotfix] fixed Permissions Error while fetching allow_stale field value from Accounts Settings (#11182)
* [hotfix] fixed Permissions Error while fetching allow_stale field value from Accounts Settings

* [minor] renamed the allow_stale_rate method to stale_rate_allowed
2017-10-25 12:17:40 +05:30
Doridel Cahanap
49a7bde6e2 [minor] Label for Training Event in Training Program Dashboard (#11280) 2017-10-25 12:15:17 +05:30
Manas Solanki
464289b726 copy the older total amount field and corrsp. changes in report (#11322) 2017-10-25 12:13:42 +05:30
Nabin Hait
1c1237537b Subscription fixes (#11292)
* Subscription fixes

* Removed recurring fields, cleanup code
2017-10-25 12:10:44 +05:30
Nabin Hait
b7483f6dfd Update item.json 2017-10-25 11:58:02 +05:30
tundebabzy
cba7a11d75 Make Variant does not copy UOM properties (#10887) (#11261)
* add `uoms` to Item Variant Settings if not already added

* add new patch to patch list

* change uoms field to no_copy:0
2017-10-25 11:57:10 +05:30
Pawan Mehta
07ab4622e8 [fix] #9824 - Calculate costing amount even if billable is unchecked (#11310)
* [fix] #9824

* fix code
2017-10-25 11:55:49 +05:30
Narciso E. Núñez Arias
47caf51efe [docs] Translate the Projects section of the Manual to Spanish (#11319)
* [docs] Translate projects module. Add index page

* [docs] Translate activity cost page from projects module.

* [docs] Translate activity type page from projects module.

* [docs] Translate the Project Costing article in project module

* [docs] Translate the Project page in projects module

* [docs] Translate the Task page in projects module

* [docs] Translate the Time Log Batch page in projects module
2017-10-25 11:53:10 +05:30
rohitwaghchaure
2672c331af Validation for duplicate offline pos (#11281) 2017-10-25 11:47:18 +05:30
Nabin Hait
f4283a3ebf Moved company field to the top in BOM (#11283) 2017-10-25 11:46:47 +05:30
Nabin Hait
8a0943ead7 Unlink reference doc on Journal Cancellation only if advance (#11285) 2017-10-25 11:46:35 +05:30
Nabin Hait
82c9352d53 Update variant description based on attribute if not already there (#11302) 2017-10-25 11:46:20 +05:30
rohitwaghchaure
311823aca1 Validate stock exists against template item (#11305) 2017-10-25 11:45:51 +05:30
Charles-Henri Decultot
7862eb444f [Hotfix] Addition of an empty tax group in the french CoA (#11306) 2017-10-25 11:44:46 +05:30
Neil Trini Lasrado
1f99bea6ce Pass sender as contact email in Opportunity (#11308)
Always pass sender as the contact email while creating an opportunity for a website enquiry.
2017-10-25 11:44:12 +05:30
Manas Solanki
a5eee4629f Fix UI tests (#11309)
* decrease the timeout

* delete the duplicate test
2017-10-25 11:42:22 +05:30
Nabin Hait
6c06e700d6 [Fix] Unallocated amount considering deductions (#11314) 2017-10-25 11:42:05 +05:30
vishalseshagiri
5c5a853894 Update customer_group.py (#11270)
Minor syntactical error !
2017-10-23 11:35:49 +05:30
Doridel Cahanap
b06f155ceb [minor] Set Quick Entry to False in Training Event (#11279) 2017-10-23 11:35:12 +05:30
Nabin Hait
f76bc27db5 Merge branch 'develop' into staging 2017-10-21 11:34:44 +05:30
Nabin Hait
b88b7eaf5b Merge branch 'hotfix' 2017-10-21 11:29:40 +05:30
Nabin Hait
7533101d4b Merge branch 'master' into develop 2017-10-21 11:29:40 +05:30
Nabin Hait
e7eda65968 bumped to version 9.1.7 2017-10-21 11:59:39 +06:00
rohitwaghchaure
5fdd26f1e7 [fix] Discount amount not reset for new order in offline pos (#11258) 2017-10-21 11:23:45 +05:30
Nabin Hait
c44290955e Minor fix in patches (#11268) 2017-10-21 11:20:18 +05:30
Nabin Hait
4825eccad5 UI test fixed for supplier quotation (#11260)
* UI test fixed for supplier quotation

* ui test fixes for purchase order

* Fixed number of assertion in student admission test

* Fixed multiple ui tests

* ui tests
2017-10-21 10:44:30 +05:30
Doridel Cahanap
5a4d5bfaf2 Add Training Program DocType, Script, Path and Doc (#11181)
* Add Training Program Doctype, Script, Config and documentation

* Add Training Program to Training Event

* [Test Case] Training Event in a Training Program
2017-10-20 11:31:15 +05:30
Nabin Hait
b4f5f14438 Timeout increased for setting __newname (#11252)
* Timeout increased for setting __newname

* UI test fixes

* fixed ui test for PO

* ui tests

* ui tests

* ui tests

* ui tests

* ui tests
2017-10-20 11:26:17 +05:30
Nabin Hait
bb60a59b96 Fixed asset test cases due to tax rule (#11247)
* Fixed asset testcases due to tax rule

* Delete tax rule record after running test cases

* Fixed test cases

* Fixed test cases

* Fixed subscription tests due to tax rule
2017-10-19 12:14:37 +05:30
Saurabh
5fa2adcca9 Merge branch 'master' into develop 2017-10-18 16:23:44 +05:30
Saurabh
12e817bad6 Merge branch 'hotfix' 2017-10-18 16:23:43 +05:30
Saurabh
47e405516b bumped to version 9.1.6 2017-10-18 16:53:43 +06:00
Saurabh
4272483f2d Merge pull request #11246 from saurabh6790/item_variant_description_fix
[minor-fix] patch fix
2017-10-18 16:15:43 +05:30
Saurabh
3173be9b17 [minor-fix] patch fix 2017-10-18 16:14:20 +05:30
Saurabh
9cb817874d Merge pull request #11245 from saurabh6790/item_variant_description_fix
[fix] remove explicit variant save
2017-10-18 16:08:23 +05:30
Saurabh
8227422124 [fix] remove explicit variant save 2017-10-18 16:03:40 +05:30
Saurabh
a7d5f94d4a [fix] Do not append description to variant if description already exists (#11204) 2017-10-18 16:02:08 +05:30
Ranjith Kurungadam
7624e7bf85 [hot-fix] sql getting translated (#11243)
* fix remove _ in frappe.sql

* use %s replacement for sql
2017-10-18 15:48:12 +05:30
Jamsheer
dd7c1b87c5 Healthcare Doctypes - Docfield Clean up (#11065)
* Healthcare Doctype Clean up - updated index, in_filter, no_copy and ect.

* Healthcare Doctype - remove frappe import
2017-10-18 12:13:15 +05:30
Makarand Bauskar
3e4ca4219f [hotfix] fixed 'ValueError: Unknown string format' error if the from_time value is null (#11162) 2017-10-18 11:16:47 +05:30
Helkyd
7ec7a45f05 Salary Detail Abbr (#11165)
When processing via Process Salary Abbr is not filled unless if Hourly pay ... this is required for later check what Component is or was added for Employee
2017-10-18 11:16:24 +05:30
Vishal Dhayagude
3e02d80636 [fix] Travis Client Side Failure (#11198) 2017-10-18 11:10:45 +05:30
Nabin Hait
5ab6ff2470 [fix] Fetch raw material rate based on last purchase rate (#11205)
* [fix] Fetch raw material rate based on last purchase rate

* Don't fetch sub-assembly item rate from BOM if not mentioned by the user
2017-10-18 11:09:11 +05:30
Brown-Harry Boma
11e964d442 Set transaction type in pricing rule only if unavailable (#11229)
* Set transaction type in pricing rule only if unavailable

* Update pricing_rule.py
2017-10-18 11:07:09 +05:30
rohitwaghchaure
a516856c32 [Fix] Getting an error duplicate name while making an invoice in draft mode (#11230) 2017-10-18 11:05:10 +05:30
Javier Wong
84f7ba8699 [hotfix] Allow Sales User and Purchase User to Read Account Settings (#11233)
* [hotfix] Allow Sales User and Purchase User to Read Account Settings

This fixes https://discuss.erpnext.com/t/not-permitted-message-for-new-quotation-and-sales-order/29261/4.

* Added back Accounts Manager Permissions
2017-10-18 11:04:15 +05:30
rohitwaghchaure
a3fe5b8528 [Fix] Disable desk access view to supplier (#11234) 2017-10-18 10:53:34 +05:30
jigneshpshah
bad5e90e46 Priority of credit limit check functionality (#11232)
CREDIT LIMIT field is at customer, customer group and company level .
Explanation given on priority of the three levels.
2017-10-18 10:53:11 +05:30
Nabin Hait
a9feddbb79 Testcase fixes (#11238)
* Restaurant test records fixed

* Fixes for test cases
2017-10-18 10:52:48 +05:30
KanchanChauhan
44734049f5 [Minor] Populate Expense Claim Description from Expense Claim Type (#11156) 2017-10-17 17:23:26 +05:30
Rushabh Mehta
bc4e2cd9c1 [added] hospitality domain (#11020)
* [added] hospitality domain

* [tests] wip

* [tests] for restaurant

* [fix] tests for new naming

* [docs] added restaurant docs

* [docs] added restaurant docs
2017-10-17 12:30:34 +05:30
Prateeksha Singh
bfb108d722 Replace c3 (#11112)
* [charts] replace in asset.js

* replace in reports
2017-10-17 12:03:02 +05:30
Nabin Hait
45a640df08 Update payment_entry_reference.json 2017-10-16 12:58:32 +05:30
Nabin Hait
53659cf0bd Update payment_entry_reference.json 2017-10-16 12:57:51 +05:30
Makarand Bauskar
80f333950b [minor] fixed AttributeError: 'GrossProfitGenerator' object has no attribute 'grouped_data' (#11195) 2017-10-16 11:27:22 +05:30
mbauskar
cd4202c2f7 Merge branch 'master' into develop 2017-10-15 19:10:56 +05:30
mbauskar
d3214fed57 Merge branch 'hotfix' 2017-10-15 19:10:55 +05:30
mbauskar
bbbce58884 bumped to version 9.1.5 2017-10-15 19:40:55 +06:00
rohitwaghchaure
8bf7230fcc [Fix] New invoice showing old paid amount if POS Profile is not created (#11160) 2017-10-15 19:09:14 +05:30
rohitwaghchaure
496174bbdf [Fix] Naming series not copy from referebce document to new document in subscription (#11196) 2017-10-15 19:08:42 +05:30
Nabin Hait
4072d71769 Delete api.py 2017-10-11 23:53:57 +05:30
Saurabh
5ffed60916 Merge branch 'master' into develop 2017-10-11 14:39:11 +05:30
Saurabh
8854438830 Merge branch 'hotfix' 2017-10-11 14:39:10 +05:30
Saurabh
15411fcf70 bumped to version 9.1.4 2017-10-11 15:09:10 +06:00
rohitwaghchaure
76a9cefc9c Merge pull request #11151 from rohitwaghchaure/minor_fix_title
[minor] Title not showing in payment modal
2017-10-11 12:05:29 +05:30
Rohit Waghchaure
4f7873b9df [minor] Title not showing in payment modal 2017-10-11 12:03:49 +05:30
Saurabh
ad9afe68f3 Merge pull request #11119 from rohitwaghchaure/default_company_pos
[enhance] Provision to select company in the POS screen if company is not defined in the global defaults
2017-10-11 12:00:56 +05:30
Saurabh
41e2b98b63 Merge pull request #11137 from mbauskar/healthcare
[hotfix] passed localise item_group value for create_lab_test_itemsfield
2017-10-11 12:00:12 +05:30
rohitwaghchaure
4eb5286c4b Merge pull request #11147 from rohitwaghchaure/total_amount_and_barcode_issue_pos
[Fix] Barcode and total amount issue in online POS
2017-10-11 11:13:30 +05:30
Rohit Waghchaure
3f309e1c20 Multiple items showing for single barcode 2017-10-11 02:14:56 +05:30
Rohit Waghchaure
9bb81ee1cb [fix] Total amount showing wrong in the payment modal if user has changed the qty after payment 2017-10-11 01:54:36 +05:30
Makarand Bauskar
4cdb9dee09 [minor] changed the modified date for the subscription doctype (#11142) 2017-10-10 18:41:00 +05:30
mbauskar
ee9da67173 [hotfix] passed localize item_group value for create_lab_test_itemsfield 2017-10-10 12:20:45 +05:30
Saurabh
9893a2d608 Merge branch 'master' into develop 2017-10-10 11:22:39 +05:30
Saurabh
e78601b040 Merge branch 'hotfix' 2017-10-10 11:22:38 +05:30
Saurabh
47b2a5f7d1 bumped to version 9.1.3 2017-10-10 11:52:38 +06:00
Saurabh
5ba4c4c49c Merge pull request #11132 from saurabh6790/upload_attendance_tool
[fix] upload attendance with with no_socketio param
2017-10-10 11:15:27 +05:30
Faris Ansari
172f28fa06 Merge pull request #11133 from netchampfaris/fix-hub-sync
fix Hub Sync plan
2017-10-09 19:31:08 +05:30
Faris Ansari
d635a2646b fix Hub Sync plan 2017-10-09 19:30:11 +05:30
Saurabh
f347e23556 [fix] upload attendacne with with no_socketio param 2017-10-09 16:13:21 +05:30
mbauskar
966b3c156a [conflicts] resolved merge conflicts 2017-10-09 15:20:30 +05:30
mbauskar
fbbb8695f3 Merge branch 'hotfix' 2017-10-09 15:18:52 +05:30
mbauskar
f9577652a0 bumped to version 9.1.2 2017-10-09 15:48:51 +06:00
Rohit Waghchaure
d270748eea [Fix] Provision to select company in the POS screen if company is not defined in the global defaults 2017-10-09 12:54:26 +05:30
Doridel Cahanap
5ba39f3f83 Add has_certificate and level fields in Training Event (#11093) 2017-10-09 12:45:28 +05:30
tundebabzy
2622d370c6 deal zero division possibility (#11098) 2017-10-09 12:44:24 +05:30
rohitwaghchaure
e181dd4c24 [patch] To add healthcare domain (#11105) 2017-10-09 12:43:36 +05:30
tundebabzy
7f9d75521e Confirmation desired before cancelling appointment (#10996) (#11106)
* shows confirm dialog when user clicks cancel

* indentation and frm as per review
2017-10-09 12:43:18 +05:30
Makarand Bauskar
eaf0abedd4 [hotfix] ignore if student email address field value is None (#11116) 2017-10-09 12:42:18 +05:30
Manas Solanki
f91ad75b5a test, patch, docs for student admission (#11075) 2017-10-09 12:41:24 +05:30
Doridel Cahanap
5cb6c38a34 Add Calendar in Training Event Doctype (#11090) 2017-10-06 11:50:05 +05:30
rohitwaghchaure
6f5853b97a Merge pull request #11092 from rohitwaghchaure/pos_total_issue
Show total instead of net total
2017-10-06 11:17:24 +05:30
Rohit Waghchaure
62ce218fc2 Show total instead of net total 2017-10-06 11:16:46 +05:30
rohitwaghchaure
1b0f3ec666 Merge pull request #11089 from rohitwaghchaure/offline_pos_v9
[Fix] Discount field not displaying in offline POS
2017-10-06 09:51:30 +05:30
Rohit Waghchaure
beeba8b37a [Fix] Discount field not displaying in offline POS 2017-10-06 09:50:43 +05:30
rohitwaghchaure
d7636b2b19 Merge pull request #11083 from rohitwaghchaure/pos_print_format_issue
[fix] Online print format in pos profile field not displaying
2017-10-06 09:44:27 +05:30
Rohit Waghchaure
b870d0081b [fix] Online print format in pos profile field not displaying 2017-10-06 09:31:40 +05:30
Nabin Hait
7eaeec951d Merge branch 'schilgod-develop' into develop 2017-10-05 19:54:17 +05:30
Nabin Hait
5a834209d0 Cleanup of PO schedule date pull requests 2017-10-05 19:51:10 +05:30
Faris Ansari
e3a5899980 [hub] Add hub category filters, fix minor issues (#11079) 2017-10-05 19:43:08 +05:30
Stavros Anastasiadis
455c3ebb27 Add as optional field link Company (#11068) 2017-10-05 18:45:37 +05:30
Stavros Anastasiadis
58b587834e Provide a minor warning message if no stock levels are availiable (#11074)
* Provide a minor warning message if no stock levels are availiable

* Update item_dashboard.js
2017-10-05 18:44:50 +05:30
Stavros Anastasiadis
e31757b001 Show Stock Level section only to stock maintain items (#11073) 2017-10-05 18:41:51 +05:30
rohitwaghchaure
e0dfd1608e [Fix] Auto add item in the cart if sinfle items found in the serach (#11072) 2017-10-05 18:30:51 +05:30
Nabin Hait
bf3b54f658 Merge branch 'schilgod-material_request' into develop 2017-10-05 18:30:11 +05:30
Nabin Hait
395cf4689b Cleanup of schedule date functionality in Material Request 2017-10-05 18:27:37 +05:30
Prateeksha Singh
925e9776e8 [hub] rename is_hub_item to is_item_from_hub (#11069)
* [hub] rename is_hub_item to is_item_from_hub

* [rename] is_hub_item to is_item_from_hub
2017-10-05 17:17:41 +05:30
AravindPranera
9c0d30a087 Fetching Document ID also in Email Subject while clicking "Send Supplier Emails" button (#10874) 2017-10-05 17:08:32 +05:30
Utkarsh Goswami
4cb4d2f155 Tests for payment entry against purchase invoice (#10930) 2017-10-05 16:51:42 +05:30
Utkarsh Goswami
975d28307a Payroll feature (#10900) 2017-10-05 15:59:51 +05:30
rohitwaghchaure
607b5d4985 [Fix] Negative qty issue in POS (#11070)
* [Fix] Negative qty issue in POS

* Update point_of_sale.js
2017-10-05 15:57:58 +05:30
Stavros Anastasiadis
ea390effa5 Add multirows in Attendees selection (#11067) 2017-10-05 15:31:25 +05:30
Nabin Hait
31e6f75dbf Merge branch 'Helkyd-develop' into develop 2017-10-05 15:29:05 +05:30
Nabin Hait
34ad2e6a60 Use format_currency only if fieldtype is currency 2017-10-05 15:28:43 +05:30
Nabin Hait
f8ad0cbe70 Merge branch 'develop' of https://github.com/Helkyd/erpnext-1 into Helkyd-develop 2017-10-05 15:02:50 +05:30
Manas Solanki
0518001bdc Changes in Student Admission (#11019)
* configurable student admission

* validate dob and admission date from student admission

* add in hooks and fix codacy
2017-10-05 14:31:31 +05:30
Doridel Cahanap
25db832be1 [minor] Add "Attendance" in grid view for Training Event Employee (#11063) 2017-10-05 14:20:43 +05:30
Makarand Bauskar
f23788bb7d [hotfix] Show Make button only for Email communication (#10876) 2017-10-05 14:19:45 +05:30
mbauskar
74ce391303 Merge branch 'master' into develop 2017-10-05 13:36:50 +05:30
mbauskar
671c6610de Merge branch 'hotfix' 2017-10-05 13:36:49 +05:30
mbauskar
8c3d19e2ab bumped to version 9.1.1 2017-10-05 14:06:49 +06:00
rohitwaghchaure
4a5ac7cea6 Merge pull request #11066 from rohitwaghchaure/pos_loading_issue
[Fix] Rate not fetched in the POS, User trying to add an item in the cart before loading of frm
2017-10-05 13:34:22 +05:30
Rohit Waghchaure
f7a856b913 [Fix] Rate not fetched in the POS, User trying to add an item in the cart before loading of frm 2017-10-05 13:31:29 +05:30
Nabin Hait
26507d7867 Removed deprecated hub functions 2017-10-05 13:10:32 +05:30
Nabin Hait
d6d99e0d59 Removed duplicate field related to hub from Item 2017-10-05 12:39:42 +05:30
Nabin Hait
729aa2025a Show commission section for pos as well (#11059) 2017-10-05 12:21:36 +05:30
Nabin Hait
7d4fd35aa3 Add POS Settings link in Accounts module (#11060) 2017-10-05 12:20:33 +05:30
rohitwaghchaure
e87a076f1d Update link in the pos for offline and online mode from pos settings (#11061) 2017-10-05 12:20:20 +05:30
Faris Ansari
fd345f8e90 Hub (#10934)
* [WIP]Hub

* [listing] Show items, users and item_groups

* Show filters

* [start] cart, api for rfq and opp

* rfq working

* [wip] keys

* wip quotes

* [hub] register/unregister

* [hub] rename password to access_token, remove passed company field

* [hub] publishing cases, api call wrapper

* [hub] add and remove fields working

* [hub] fix flags, update on client save working

* [hub] new hub page, client item CUD at hub working

* listing, standard rate, local site hack

* item listing, item page, search, back to home

* [hub] implement hub company

* [hub] company filter

* [hub] basic rfq-ing, item page cleanup

* categories wip

* [hub] use get_doc_before_save()

* [hub] send opportunity message to hub, api to make locally

* [hub] enqueueing in hub api request wrapper

* cleanup

* [hub] refactor shopping cart's product.py to reuse

* sync dynamic item fields daily

* Scheduler heartbeat check

* [wip] hub categories

* [hub] wip enqueued callbacks

* [hub] outgoing messages, fixing callback loop

* [hub] bug: callback save after primary save

* [hub] pricing, stock, currency

* [hub] replace send_hub_request with make_and_enqueue

* add hub.less, refactor code

* Remove template html files, add styling for hub item cards

* fix paging

* add breadcrumb

* Add sidebar

* [hub] add company page, change country

* [hub] order_by filters

* [hub] make hub category a tree

* [hub] enqueue batched item enqueueing

* [hub] requested products page

* [minor]

* update hub url

* [fix] url

* [fix] more reform

* fix recursion

* [hub] data migration plans as jsons

* Hub register, create data connector, sync with run

* [add] user registration by session user

* Removed hub_message

* Remove sync code from hub_settings

* Remove hub methods from item.py

* Update Hub Sync plan

* Hub unregister

* Update Hub connector on reregister

* Dont delete Hub Connector on unregister

* Enable hub on success response

* Add new hub whitelisted methods

* [hub] list working

* Hub register from hub page

* [hub] Add hub logo in desk icon, link to page

* [hub] hide page head on empty state

* [hub] make rfq

* [hub] push opportunity doc, poll for opportunity docs

* add fields to item mapping

* update hub mappings

* Make RFQ

* [hub] item, home routing

* Make rfq and send opportunity refactor

* [hub][fix] remote lead data

* images passed as base64

* set default company on register

* Revert "images passed as base64"

This reverts commit 0b033a5fb7072b2d39a1b87a47dc41e7af707bb4.

* Add sync to hub page

* Prompt for publish items to hub

* add post process to hub document to lead

* Rename Hub document to Hub message, create opportunity in post process
2017-10-05 11:17:30 +05:30
Nabin Hait
ff689a658f Merge branch 'staging' 2017-10-04 18:21:35 +05:30
Nabin Hait
b290e3a4e7 bumped to version 9.1.0 2017-10-04 18:51:34 +06:00
Nabin Hait
77f0822abe Merge branch 'develop' into staging 2017-10-04 18:11:16 +05:30
Nabin Hait
f83bc51e81 Merge branch 'master' into staging 2017-10-04 18:05:21 +05:30
Nabin Hait
fc712aea32 Merge branch 'master' into develop 2017-10-04 18:05:20 +05:30
Nabin Hait
7105c4b76c Merge branch 'hotfix' 2017-10-04 18:05:19 +05:30
Nabin Hait
54c725dcd1 bumped to version 9.0.9 2017-10-04 18:35:19 +06:00
rohitwaghchaure
1e2c554e61 [Fix] Stock entry multi uom batch validation issue (#11049) 2017-10-04 17:52:49 +05:30
tundebabzy
65dfd09947 fix wrong variable name (#11050) 2017-10-04 17:51:44 +05:30
Javier Wong
61287e3c53 [fix] Change Sample Item Error Message to Zero Valuation Rate (#10935)
Change Sample Item Error Message to Zero Valuation Rate
2017-10-04 16:01:34 +05:30
Makarand Bauskar
1b67d71139 [minor] add the Lead in email account -> append_to field (#10983) 2017-10-04 15:55:56 +05:30
Doridel Cahanap
32456b0f14 [minor edits] BOM Stock Report (#11012)
* HTML for BOM Stock Report to show filters in PDF

* Added BOM Stock Report in Manufacturing Config under Report
2017-10-04 15:54:44 +05:30
Nabin Hait
3d0d4b2157 update subscription period only if relevant date field exists (#11046) 2017-10-04 15:51:55 +05:30
Nabin Hait
7e5a9f5c0e Update new bom rate while replacing BOM (#11045) 2017-10-04 15:51:34 +05:30
KanchanChauhan
d3e21fff66 [Minor] Employee name as standard filter (#11043) 2017-10-04 15:20:34 +05:30
Nabin Hait
5171956646 Merge branch 'master' into staging 2017-10-04 14:52:33 +05:30
Nabin Hait
0cc93538ed Merge branch 'hotfix' 2017-10-04 14:52:32 +05:30
Nabin Hait
b779644493 Merge branch 'master' into develop 2017-10-04 14:52:32 +05:30
Nabin Hait
c83e793ce8 bumped to version 9.0.8 2017-10-04 15:22:31 +06:00
Revant Nandgaonkar
4d68e03a97 [Fix] Job Opening Web Form breadcrumb (#11029) 2017-10-04 14:35:21 +05:30
Makarand Bauskar
eaec4695f7 [hotfix] filter doctype if the doctype has subscription field (#11038) 2017-10-04 14:34:45 +05:30
rohitwaghchaure
5049edb494 [Fix] Discount and serial no search issue (#11040) 2017-10-04 14:33:12 +05:30
Makarand Bauskar
d17bea0a31 [hotfix] check minimum actual start time and actual end time before updating PO Operations (#11041)
* [hotfix] check minimum actual start time and actual end time before updating PO Operations

* Update production_order.py
2017-10-04 14:30:12 +05:30
Saurabh
444bfff1ff [fix] resolved merge conflicts 2017-10-03 18:03:18 +05:30
Saurabh
ee4a2dd26f [fix] resolved merge conflicts 2017-10-03 18:02:09 +05:30
Saurabh
f6580268e6 Merge branch 'hotfix' 2017-10-03 18:00:32 +05:30
Saurabh
e3a468ed1b bumped to version 9.0.7 2017-10-03 18:30:31 +06:00
rohitwaghchaure
9e6f2a49e8 Merge pull request #11033 from rohitwaghchaure/subscription_next_data_fix
[Fix] Subscription next schedule date, cancel issue, added from and to date
2017-10-03 17:48:53 +05:30
Rohit Waghchaure
445e8a2e57 [Fix] Subscription end date, cancel issue, added from and to date 2017-10-03 17:45:11 +05:30
Nabin Hait
7b6eaee05b Fixes to handle async events (#11018)
* Fixes to handle async events

* transaction.js code cleanup

* Don't map taxes and charges while making PO from SO for drop-ship

* Removed print
2017-10-03 01:09:46 +05:30
rohitwaghchaure
c26e3f1569 Merge pull request #11024 from rohitwaghchaure/payment_issue_in_pos
[Fix] Old invoice payment amount showing in the payment modal while making payment
2017-10-02 22:29:49 +05:30
Rohit Waghchaure
c4e52e5f95 [Fix] Old invoice payment amount showing in the payment modal while making payment 2017-10-02 21:20:54 +05:30
Nabin Hait
7eba1a35d3 Controller init args fix (#11015)
* Controller init args fix

* cleanup useless code
2017-10-02 15:59:27 +05:30
Nabin Hait
1f10d693e9 Don't set currency as company currency if default currency is different (#11011) 2017-10-02 13:20:51 +05:30
Nabin Hait
53e8989699 Merge branch 'master' into staging 2017-10-02 12:28:27 +05:30
Nabin Hait
8919669ac2 Merge branch 'master' into develop 2017-10-02 12:28:27 +05:30
Nabin Hait
d977333a99 Merge branch 'hotfix' 2017-10-02 12:28:26 +05:30
Nabin Hait
3a2834c7ad bumped to version 9.0.6 2017-10-02 12:58:26 +06:00
rohitwaghchaure
88491715e0 [Fix] select batch not displaying in the modal, duplicate invoice making after sync (#11005) 2017-10-02 12:13:36 +05:30
Nabin Hait
0bdf1e5ef1 Merge branch 'master' into staging 2017-10-02 12:09:01 +05:30
Nabin Hait
f059e7be35 Merge branch 'master' into develop 2017-10-02 12:09:00 +05:30
Nabin Hait
00a48ad4e5 Merge branch 'hotfix' 2017-10-02 12:09:00 +05:30
Nabin Hait
def308a433 bumped to version 9.0.5 2017-10-02 12:38:59 +06:00
Makarand Bauskar
cb38e599e5 [minor] don't create lead if customer contact is already created against contact_email (#10976)
* [minor] don't create lead if customer contact is already created against contact_email

* [tests] added tests cases for opportunity to check if lead is required or not
2017-10-02 11:40:43 +05:30
Nabin Hait
9b98d7fa14 Gst doctype roles (#10984)
* Removed default permission from GST doctypes

* default permission from GST doctypes
2017-10-02 11:38:40 +05:30
Makarand Bauskar
b1bf502119 [hotfix] validate company name on 'The Brand' Slide instead of 'Your Organization' (#11007) 2017-10-02 11:38:03 +05:30
Nabin Hait
cb48404bd2 Revert "Fixes for uom in get_item_details (#10986)" (#11009)
This reverts commit 5b58e489a8.
2017-10-02 11:37:18 +05:30
Nabin Hait
5b58e489a8 Fixes for uom in get_item_details (#10986) 2017-10-02 11:36:10 +05:30
Sunny
38647ed832 move Purchase Order patch to v9 2017-10-02 11:37:48 +08:00
Sunny
42c74a6365 set schedule_date when creating po 2017-10-02 11:37:48 +08:00
Sunny
c6f25ba996 correct field name 2017-10-02 11:37:47 +08:00
Sunny
b387b3cca0 [fix] tests 2017-10-02 11:37:47 +08:00
Sunny
a456901e9f [fix] Codacy errors 2017-10-02 11:37:47 +08:00
Sunny
0f2b21f88b Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:37:47 +08:00
Sunny
73f4eef40f [fix] tests 2017-10-02 11:37:47 +08:00
Sunny
9ded8a7290 [fix] Codacy errors 2017-10-02 11:37:47 +08:00
Sunny
c2befc59d1 Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:37:47 +08:00
Sunny
34a8fb4100 [fix] Codacy errors 2017-10-02 11:37:47 +08:00
Sunny
47eac28f0a Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:37:47 +08:00
Sunny
869b878286 set schedule_Date when creating po 2017-10-02 11:36:24 +08:00
Sunny
f2e2e23b6b [fix] tests 2017-10-02 11:35:33 +08:00
Sunny
3a22fd1535 Add schedule_date when creating Purchase Order 2017-10-02 11:35:33 +08:00
Sunny
f07e53b7a8 [fix] tests 2017-10-02 11:35:33 +08:00
Sunny
bd121486a8 [fix] Codacy errors 2017-10-02 11:35:33 +08:00
Sunny
122981d465 Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:35:33 +08:00
Sunny
962cef470a Set PO Reqd By Date default in code, to next date 2017-10-02 11:35:33 +08:00
Sunny
0f73f90fa2 [fix] Codacy errors 2017-10-02 11:35:33 +08:00
Sunny
69e88ffa39 Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:35:33 +08:00
schilgod
f29969a5cc update test records 2017-10-02 11:35:32 +08:00
Sunny
e3ed8b7cb3 [fix] tests 2017-10-02 11:35:32 +08:00
Sunny
9626ed79fa Add patch to update schedule date of submitted Purchase Orders 2017-10-02 11:35:32 +08:00
Sunny
c429a6e688 [fix] Codacy errors 2017-10-02 11:35:32 +08:00
Sunny
2315a79b5f Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:35:32 +08:00
Sunny
9da25f568d Set PO Reqd By Date default in code, to next date 2017-10-02 11:35:32 +08:00
Sunny
9d497a984b [fix] Codacy errors 2017-10-02 11:35:32 +08:00
Sunny
bb03ec103b Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-10-02 11:35:32 +08:00
Helkyd
4c58588d25 Improve Salary Register
Check if fieldname is a number to format.

Start the Html Salary with hidden fields and check if they not empty and increase the width...
This will remove Blank fields from the report.
2017-10-01 20:20:57 +01:00
Rushabh Mehta
4b99fe15cc [version] 9.x.x-develop 2017-09-30 11:41:26 +05:30
Rushabh Mehta
b9fe14631d [fix] healthcare setup 2017-09-30 10:46:56 +05:30
Nabin Hait
01b96a0e31 Fixes for uom in get_item_details 2017-09-29 18:57:41 +05:30
Nabin Hait
79a1d2a3b0 Fixes for uom in get_item_details 2017-09-29 18:15:40 +05:30
Nabin Hait
6488645d42 Fixed ui tests for production order 2017-09-29 16:38:28 +05:30
Rushabh Mehta
b46900a4cb Merge branch 'master' into staging 2017-09-29 16:22:02 +05:30
Rushabh Mehta
912ae24ca2 Merge branch 'master' into develop 2017-09-29 16:22:02 +05:30
Rushabh Mehta
e292c83114 Merge branch 'hotfix' 2017-09-29 16:22:01 +05:30
Rushabh Mehta
e1a4b3e4bc bumped to version 9.0.4 2017-09-29 16:52:01 +06:00
Rushabh Mehta
d3a48a83fd [fix] bom.py, dont use keyword 2017-09-29 15:50:17 +05:30
Rushabh Mehta
80d24f83f8 [fix] item variant description 2017-09-29 15:39:03 +05:30
Pawan Mehta
5d8fd477bd [fix] #10840 (#10844) 2017-09-29 15:23:54 +05:30
Javier Wong
bf37995745 [Enhancement] Sales and Purchase Default UOM (#10929)
Option for specifying an optional default Sales and Purchase UOM at the item master level.
2017-09-29 15:23:08 +05:30
tundebabzy
5510d0751d correctly set frm company currency (#10944) 2017-09-29 15:21:59 +05:30
Shreya Shah
b79c4a9ff6 Getting last purchase price of an item (#10897)
* Added a column last purchase rate

* Removed button last purchase rate

* Get last purchase rate on adding an item

* Added test case for last purchase rate

* Replaced cur_frm with frm

* Update purchase_order.js
2017-09-29 15:20:48 +05:30
Francisco Roldán
1b61dfd9ea translated (#10886) 2017-09-29 15:19:12 +05:30
Shridhar Patil
3f7d96ecba Unassign from todo. (#10896)
Unassign from todo when the status is changed to Closed or Cancelled
2017-09-29 15:18:43 +05:30
Faris Ansari
367b90e3ae Add Data Import Tool desktop icon (#10916)
fixes #8332
2017-09-29 15:17:48 +05:30
Nabin Hait
945f502748 Fixes for updating item variant from template (#10975)
* Fixes for updating item variant from template

* More fixes for test cases
2017-09-29 15:11:50 +05:30
Makarand Bauskar
9c339145b2 [Enhance] Custom notification messages for subscription documents (#10970)
* [minor] configurable subscription email message and subject for notification

* [minor] added description for subject field
2017-09-29 15:02:51 +05:30
Rushabh Mehta
3c14c5a16c [fix] tax_rule.py args 2017-09-29 13:21:22 +05:30
Nabin Hait
bdb4c542e7 default permission from GST doctypes 2017-09-29 10:39:32 +05:30
Nabin Hait
6d61a45f42 Removed default permission from GST doctypes 2017-09-29 10:35:21 +05:30
Nabin Hait
c314485d55 Fixes based on test case 2017-09-28 18:55:49 +05:30
Nabin Hait
3b04cfc812 minor fix 2017-09-28 18:55:49 +05:30
mbauskar
79ba422273 Merge branch 'develop' into staging 2017-09-28 16:32:33 +05:30
rohitwaghchaure
0dc3c1b114 Merge pull request #10953 from rohitwaghchaure/has_batch_item_in_demo
[minor] Added batch item in the demo data
2017-09-28 16:07:01 +05:30
schilgod
0f6fff6f0c item price track_changes default to 1 (#10958) 2017-09-28 15:28:59 +05:30
Rushabh Mehta
2b87d100fa [fix] https://github.com/frappe/erpnext/issues/10956 2017-09-28 15:21:36 +05:30
Rohit Waghchaure
c4ee77a3cc [minor] Added batch item in the demo data 2017-09-28 15:19:26 +05:30
Sunny
3ec6960478 move Material Request patch to v9 2017-09-28 15:26:20 +08:00
Sunny
33670bba47 fix reorder_item 2017-09-28 15:24:11 +08:00
Sunny
73f1c93cd2 fix ppt code 2017-09-28 15:24:11 +08:00
Sunny
bf68611567 clean code 2017-09-28 15:24:11 +08:00
Sunny
0d91d3f572 add schedule_date while creating Material Request 2017-09-28 15:23:52 +08:00
Sunny
892ec599d4 [fix] tests 2017-09-28 15:23:09 +08:00
Sunny
65cd9f2284 Add patch to update schedule date of submitted Purchase Orders 2017-09-28 15:23:09 +08:00
Sunny
799d69baba [fix] Codacy errors 2017-09-28 15:22:49 +08:00
Sunny
71866e06f3 Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-09-28 15:22:49 +08:00
Sunny
284ceb7abe Set PO Reqd By Date default in code, to next date 2017-09-28 15:22:49 +08:00
Sunny
65c7a6947a [fix] Codacy errors 2017-09-28 15:22:49 +08:00
Sunny
f7a8277d12 Add Purchase Order schedule_date field, similar to delivery_date in Sales Order 2017-09-28 15:22:49 +08:00
Sunny
12cb07ce3c [fix] test records 2017-09-28 15:22:49 +08:00
Sunny
23a4b09d43 Add Material Request schedule_date field, similar to delivery_date in Sales Order 2017-09-28 15:22:48 +08:00
Nabin Hait
c9f9e5235b Fixed merge conflict 2017-09-28 12:31:33 +05:30
Nabin Hait
edd4fd4692 Merge branch 'hotfix' 2017-09-28 12:30:48 +05:30
Nabin Hait
ca916a73de bumped to version 9.0.3 2017-09-28 13:00:48 +06:00
Makarand Bauskar
53e19075d1 [hotfix] fixes and refactored Quoted Item Comparison report (#10954) 2017-09-28 12:30:04 +05:30
Rushabh Mehta
a0ba5594f9 [fix] production_order.py via error report 2017-09-28 11:26:24 +05:30
rohitwaghchaure
16645803f9 [fix] Added billing address gstin number in the sales invoice and delivery note as well in the sales gst reports (#10872) 2017-09-28 11:05:03 +05:30
rohitwaghchaure
94799a8b93 [fix] ‘NoneType’ object is not iterable onload of POS (#10941) 2017-09-28 10:56:27 +05:30
Nabin Hait
fce14fdcf0 Fixed merge conflict 2017-09-27 17:21:21 +05:30
Nabin Hait
7baacb7f74 Merge branch 'hotfix' 2017-09-27 17:19:55 +05:30
Nabin Hait
76615c8001 bumped to version 9.0.2 2017-09-27 17:49:55 +06:00
Prateeksha Singh
283922daa2 [fix] Check for stock_qty, else use qty (#10937) 2017-09-27 17:12:28 +05:30
rohitwaghchaure
da8de2f0c7 Re-order patch sequence (#10936) 2017-09-27 17:11:40 +05:30
rohitwaghchaure
0060993eab Merge pull request #10931 from rohitwaghchaure/customer_group_issue_for_lead
[fix] 'NoneType' object is not iterable while saving quotation
2017-09-27 16:08:35 +05:30
Rohit Waghchaure
566a0a05c8 [fix] 'NoneType' object is not iterable while saving quotation 2017-09-27 15:57:48 +05:30
Rushabh Mehta
f702d72c35 [minor] [performance] push hsn code creation after setup (#10928) 2017-09-27 15:31:30 +05:30
Nabin Hait
76e1ca35ad Merge branch 'master' into develop 2017-09-27 13:05:21 +05:30
Nabin Hait
e0a845c356 Merge branch 'hotfix' 2017-09-27 13:05:20 +05:30
Nabin Hait
eb686f8b1a bumped to version 9.0.1 2017-09-27 13:35:20 +06:00
Brown-Harry Boma
d3fa19143d Properly redirect supplier after quotations submit (#10903) 2017-09-27 12:53:38 +05:30
Makarand Bauskar
70eaf2da95 [minor] removed the default precision for the margin_rate_or_amount field (#10923) 2017-09-27 12:49:16 +05:30
rohitwaghchaure
103b239a31 Merge pull request #10925 from rohitwaghchaure/pos_issues_v9
[fix] Discount amount not working for POS
2017-09-27 12:20:30 +05:30
Rohit Waghchaure
87e994e0a2 [fixed] Disocunt amount not working for POS 2017-09-27 12:16:58 +05:30
rohitwaghchaure
45d45f4247 [hotfix] Wrong calculation of total in taxes and totals (#10924) 2017-09-27 11:49:13 +05:30
Prateeksha Singh
946e182564 install company fixtures while creating company (#10904)
* install company fixtures while creating company

* [fix] remove from setup_complete
2017-09-27 11:44:39 +05:30
Frappe PR Bot
9aff73d156 [Translation] Updated Translations (#10901) 2017-09-26 17:18:42 +05:30
Prateeksha Singh
df8fbd7d72 [fix] batch qty checked against stock_qty field (#10906) 2017-09-26 17:16:03 +05:30
Nabin Hait
51a07d19c8 Merge branch 'master' into develop 2017-09-26 15:59:15 +05:30
Nabin Hait
8ff0a64ac2 Merge branch 'staging' 2017-09-26 15:59:12 +05:30
Nabin Hait
c0b4f0e81b bumped to version 9.0.0 2017-09-26 16:29:12 +06:00
Nabin Hait
b0ba55e52f Set bill no while making payment entry from purchase invoice 2017-09-26 15:56:58 +05:30
rohitwaghchaure
d4c2d77bba [fix] POS not working if user clicks on back button from form view (#10912) 2017-09-26 13:27:06 +05:30
Prateeksha Singh
ada8ba96b3 [setup] remove translations from action name (#10911) 2017-09-26 13:07:24 +05:30
Nabin Hait
773e686fb1 change log for version 9 2017-09-26 12:41:43 +05:30
Nabin Hait
afe9eabd3c Merge branch 'master' into develop 2017-09-25 16:36:47 +05:30
Nabin Hait
360c1efd18 Merge branch 'master' into staging 2017-09-25 16:36:47 +05:30
Nabin Hait
a0b85cd1ec Merge branch 'hotfix' 2017-09-25 16:36:45 +05:30
Nabin Hait
9ef023b10f bumped to version 8.11.6 2017-09-25 17:06:44 +06:00
Nabin Hait
0d0811ca14 reload print style 2017-09-25 16:33:45 +05:30
Nabin Hait
39c2f75e6d Merge branch 'master' into staging 2017-09-25 16:03:32 +05:30
Nabin Hait
cb5e1e550f Merge branch 'master' into develop 2017-09-25 16:03:31 +05:30
Nabin Hait
3ab938ea34 Merge branch 'hotfix' 2017-09-25 16:03:29 +05:30
Nabin Hait
7da3c46ef2 bumped to version 8.11.5 2017-09-25 16:33:29 +06:00
Nabin Hait
3b61552836 Revert "Advance against expense claim (#10632)" (#10877)
This reverts commit cdd6ded790.
2017-09-25 11:27:39 +05:30
Nabin Hait
4ebac3380d reload print style 2017-09-23 15:50:39 +05:30
tundebabzy
e4be3f8dc9 use generator when updating and notify user of long process (#10777) 2017-09-21 18:27:33 +05:30
Nabin Hait
cdd6ded790 Advance against expense claim (#10632)
* Adds Whitelist Method for Advance Entry

* Adds changes required for managing Advance Payments in Expense Claim including new fields and documentation. Also resolved merge conflict by using the more recent modified date

* Adds changes for managing advance payments using Default Account and Party

* Removed console.log from the JS file

* Advance Payment Patch - Fixed Codacy errors

* Removed stray file

* Fixed conflicts due to changes in upstream

* Fixed Codacy errors

* Fixed Codacy errors

* Fixed Codacy errors

* Fixed Codacy errors

* Fixed Codacy errors

* Fixed pending Codacy error

* Updated JS code by removing cur_frm which is soon to be deprecated

* Advance against Expense Claim: cleanup and fixes

* Test case fixed
2017-09-21 18:03:45 +05:30
Nabin Hait
3d5d858933 set total in tax table if category not valuation and consider deductions (#10870) 2017-09-21 16:15:30 +05:30
Nabin Hait
fb142f5283 Merge branch 'AravindPranera-develop' into develop 2017-09-21 15:52:06 +05:30
Nabin Hait
6d78f7b862 Fixed indentation 2017-09-21 15:51:42 +05:30
Nabin Hait
5478a7fa67 Merge branch 'develop' of https://github.com/AravindPranera/erpnext-1 into AravindPranera-develop 2017-09-21 15:48:18 +05:30
Nabin Hait
2851dfad99 Set fields in Item Variant Settings which should be copied from template to variant 2017-09-21 15:41:57 +05:30
Rohit Waghchaure
5b05335e89 added patch and set default fields after completion of setup wizard 2017-09-21 15:41:57 +05:30
Rohit Waghchaure
0e28fccb34 [Enahance] Update variants fields defined in the Item Varianst Settings, if template updated 2017-09-21 15:41:57 +05:30
tundebabzy
ab5b03011d Enhance Currency Exchange Management (#10482)
* add new settings in Accouts Settings

* patch for new settings

* refactor `get_exchange_rate`

* adds validation

* tests validation

* disables conversion rate field if stale rates not allowed

* more test cases

more test case...

test `get_exchange_rate` behaviour with stale not allowed in sett..

fix currency exchange test case

do housekeeping after running accounts settings test

* clean up

* documentation

* make use of correct api url

* Fix tests failing due to wrong exchange rate from fixer.io

* remove mandatory constraint from `allow_stale`

* added info to documentation
2017-09-21 14:50:39 +05:30
rohitwaghchaure
12fd8a6047 [fix] User not able to complete the production order because of decimal issue (#10868) 2017-09-21 14:39:10 +05:30
Nabin Hait
24ec3c7dcb Fixed merge conflict 2017-09-21 12:53:41 +05:30
Vishal Dhayagude
c4c2c56af2 env variable added (#10847) 2017-09-21 12:07:56 +05:30
Prateeksha Singh
705d885b64 [progress] R/W permission for all roles (#10866) 2017-09-21 12:02:18 +05:30
Manas Solanki
1c1dd08a34 only validate party account and ref doc party account in selected case (#10863)
* only validate party account and ref doc party account in selected case

* fix for fee structure test

* fix the assessment result test
2017-09-21 12:01:20 +05:30
Nabin Hait
b2dca79d89 Updated modified timestamp in sales/purchase transaction doctypes 2017-09-20 09:56:06 +05:30
Nabin Hait
6960a76adc Fixes related to schools fees 2017-09-19 17:23:03 +05:30
Manas Solanki
0664d6ed8b real time fee creation status via socketio 2017-09-19 17:23:03 +05:30
Manas Solanki
1bcc6c661a minor changes 2017-09-19 17:23:03 +05:30
Manas Solanki
9b44c16a32 add the fee schedule in config 2017-09-19 17:23:03 +05:30
Manas Solanki
1299d56e85 cleanup of the fee module 2017-09-19 17:23:03 +05:30
Manas Solanki
8c88af23ef added the test case for the fees 2017-09-19 17:23:03 +05:30
Manas Solanki
d1d2633658 removed the fee schedule 2017-09-19 17:23:03 +05:30
Manas Solanki
152ba1eccb fixes as per the review 2017-09-19 17:23:03 +05:30
Manas Solanki
49c52f7639 renamed one doctype to the fee schedule 2017-09-19 17:23:03 +05:30
Manas Solanki
4e0559bc79 make payment entry for the fees 2017-09-19 17:23:03 +05:30
Manas Solanki
2b39d5d6d5 make gl_entry on submission of fees 2017-09-19 17:23:02 +05:30
Manas Solanki
e4acf763a5 make payment request for the fee 2017-09-19 17:23:02 +05:30
Manas Solanki
f073814635 added fee request doctype 2017-09-19 17:23:02 +05:30
Nabin Hait
2e4de83df6 Rounding Adjustment via a separate field, instead of last tax row (#10659)
* Rounding Adjust via a separate field, instead of last tax row

* Fixed test cases
2017-09-19 14:53:16 +05:30
rohitwaghchaure
f551b43a94 Merge pull request #10841 from rohitwaghchaure/subscription_patch_fix_docststus
[fix] Subscription patch broken if reference document has been cancelled
2017-09-19 13:24:04 +05:30
Rohit Waghchaure
c15a3bd379 [fix] Subscription patch broken if reference document has been cancelled 2017-09-19 12:53:11 +05:30
Nabin Hait
caf9891075 Fixed merge conflict 2017-09-19 12:06:22 +05:30
Nabin Hait
bd4b80e3d8 Merge branch 'master' into develop 2017-09-19 12:05:41 +05:30
Nabin Hait
9930eb0a7a Merge branch 'hotfix' 2017-09-19 12:05:39 +05:30
Nabin Hait
703e837125 bumped to version 8.11.4 2017-09-19 12:35:39 +06:00
rohitwaghchaure
4f0f144142 Merge pull request #10831 from rohitwaghchaure/cherry_pick_subscription_staging_to_develop
Cherry pick staging to develop for subscription cleanup
2017-09-19 10:26:20 +05:30
Nabin Hait
cf36534eed Gross profit report considering returned items (#10734) 2017-09-18 19:13:45 +05:30
AravindPranera
cb6774e373 Files added with all functions 2017-09-18 17:37:37 +05:30
AravindPranera
1276893550 Files added with all functions 2017-09-18 17:30:20 +05:30
rohitwaghchaure
d02744b436 [fix] Subscription patch (#10827) 2017-09-18 17:23:00 +05:30
rohitwaghchaure
850eaa73b0 Move subscription module to accounts (#10772) 2017-09-18 17:23:00 +05:30
Nabin Hait
e859671eb3 Revert "Added ability to disable auto creation of Sales Invoice when customer pays a payment request (#10706)" (#10830)
This reverts commit d258372f9e.
2017-09-18 17:22:46 +05:30
Neil Trini Lasrado
d258372f9e Added ability to disable auto creation of Sales Invoice when customer pays a payment request (#10706) 2017-09-18 17:12:16 +05:30
tundebabzy
f6d738b3c5 Delivery note to billing issue (#10726) (#10766)
* allow invoices to be made from sales returns

* Update queries.py
2017-09-18 17:10:09 +05:30
Utkarsh Goswami
b98359f4a7 Payment entry (#10668) 2017-09-18 17:06:13 +05:30
Makarand Bauskar
5c1d15f015 [change-log] added change log for v9.0.0 (#10756)
* [change-log] added change log for v9.0.0

* Update v9_0_0.md
2017-09-18 17:03:21 +05:30
Manas Solanki
a22c94c246 refactored assessment result tool (#10633)
* save the assessment instead of submit

* Added comments in the artool

* remove the cur_frm and message for submitted result

* link field for the assessment result
2017-09-18 16:59:54 +05:30
Faris Ansari
aebcb17daf Show thumbnail image in daily work summary (#10605)
* Show thumbnail image in daily work summary

* Crop thumbnail image into square

* fix codacy
2017-09-18 16:58:24 +05:30
rohitwaghchaure
6cea73b834 [fix] Subscription patch (#10827) 2017-09-18 16:58:05 +05:30
Utkarsh Goswami
bd0beb6c02 [fix] unknown column in production order (#10828) 2017-09-18 16:48:45 +05:30
Utkarsh Goswami
e78d5a240a [fix] unknown column in production order (#10828) 2017-09-18 16:44:11 +05:30
Neil Trini Lasrado
de3429280b Made Template link in variant (Item Master) intro linkable (#10696)
* Made Template link in variant (Item Master) intro linkable

* Update item.js
2017-09-18 16:42:10 +05:30
Neil Trini Lasrado
8c9f2a1be6 Add communication entry to Sales Order only if payment entry email is sent to customer (#10716) 2017-09-18 16:41:49 +05:30
Prateeksha Singh
9b4f3cf9de Leaderboard cleanup (#10638)
* [leaderboard] wip

* [leaderboard] filter for selecting leaderboard criteria, single col

* [leaderboard] doctypes in sidebar

* hide graph if no results
2017-09-18 16:41:04 +05:30
Saurabh
0396674d0d Merge pull request #10826 from saurabh6790/salary_struct_fix_1
Salary struct fix
2017-09-18 16:18:35 +05:30
Saurabh
9c334c34a6 [fix]remove employee field from tab salary structure 2017-09-18 16:17:13 +05:30
Manas Solanki
e716da04ec add the newsletter in the standard portel (#10784) 2017-09-18 16:00:34 +05:30
Saurabh
590d401e5f [fix] if bom specified on purchase order item then don't pull default bom in purchase receipt (#10793)
* [fix] if bom specified on purchase order item then don't pull default bom in purchase receipt

* Update bom.js

* Update stock_entry.py
2017-09-18 15:49:19 +05:30
ci2014
9bc197cfd5 Update project.js (#10796)
* Update project.js

Move indicators to setup to be less buggy

* fixed codecy trailing whitespace issues
2017-09-18 15:44:36 +05:30
Saurabh
d7e1869a70 [fix] if item code not exists then exclude item in validate_selling_price (#10800) 2017-09-18 15:43:35 +05:30
Saurabh
3f15bf9828 [fix] query fix for match conditions (#10810) 2017-09-18 15:27:24 +05:30
Nabin Hait
9744aa21af Minor fix in tax rule 2017-09-18 15:25:33 +05:30
Adam Dawoodjee
91eda6dad4 Update creating-custom-link-field.md (#10822)
Grammer improvements
2017-09-18 15:11:57 +05:30
Zarrar
8f957ef6e6 fetching data from last route (#10816) 2017-09-18 15:11:20 +05:30
Utkarsh Goswami
11bd5fc3b1 Description moved next to item code (#10820) 2017-09-18 15:05:50 +05:30
Saurabh
2222f10720 [patch] remove employee name salary structure (#10817)
* [patch] remove employee name salary structure

* Update remove_employee_from_salary_structure_parent.py
2017-09-18 15:05:18 +05:30
Nabin Hait
bc9006ff30 Delete GST related doctypes and reports if account is from outside India (#10808) 2017-09-18 13:16:04 +05:30
rohitwaghchaure
70ef09aa8f Merge pull request #10809 from rohitwaghchaure/fixed_test_cases_issue
[fix] Test cases for tax rule
2017-09-16 22:55:16 +05:30
Rohit Waghchaure
2cb2064c6f Fixed test cases tax rule 2017-09-15 23:10:27 +05:30
Nabin Hait
21617da619 More fixes for UI tests 2017-09-15 21:22:16 +05:30
Nabin Hait
628ca2a2ec Minor fix for ui tests 2017-09-15 19:35:12 +05:30
Nabin Hait
46941e8b35 Time out increased for appraisal template 2017-09-15 18:56:49 +05:30
Prateeksha Singh
d1ce7bfff4 [fix] set item valuation rates (#10681) 2017-09-15 16:17:29 +05:30
rohitwaghchaure
dd092e30fb Move subscription module to accounts (#10772) 2017-09-15 16:16:36 +05:30
Makarand Bauskar
5ac01a2bf7 [minor] translate the action name in get_slide_settings (#10740) (#10790) 2017-09-15 12:10:29 +05:30
AravindPranera
27bbb561d2 removed whitespace 2017-09-15 11:04:14 +05:30
AravindPranera
2c1f44ecfa Trailing space removed in line 275 2017-09-15 10:57:23 +05:30
AravindPranera
c73383c34c Trailing whitespace in Line 207 and 276 2017-09-15 10:34:21 +05:30
Nabin Hait
43268bd350 Fixed salary structure tests 2017-09-14 19:39:10 +05:30
Nabin Hait
2f64f0f5fa Fixed salary structure tests 2017-09-14 19:08:15 +05:30
Nabin Hait
427172c941 Update test_salary_structure.js 2017-09-14 17:57:21 +05:30
Nabin Hait
41146657de Set default customer group and territory after install 2017-09-14 17:26:23 +05:30
Nabin Hait
092f6d3739 Fixes ui tests 2017-09-14 16:45:47 +05:30
mbauskar
f41cff27e6 resolved merge conflicts 2017-09-14 15:32:55 +05:30
mbauskar
ea832b8157 resolved merge conflicts 2017-09-14 15:32:10 +05:30
mbauskar
fd39e6f3c8 Merge branch 'hotfix' 2017-09-14 15:28:44 +05:30
mbauskar
8ea3bb0d90 bumped to version 8.11.3 2017-09-14 15:58:44 +06:00
Nabin Hait
45dce89cae Print Settings for printing taxes with zero amount (#10782)
* Print Settings for printing taxes with zero amount

* added __init__.py file to patch module v8_9
2017-09-14 15:17:38 +05:30
Rushabh Mehta
bf8e331135 [fix] unset default customer group (#10689)
* [fix] unset default customer group

* added __init__.py file for patch v8.9 directory
2017-09-14 15:03:45 +05:30
Nabin Hait
a6d78ef842 Added Supplier Bill Date in Itemised Purchase Register (#10783) 2017-09-14 15:01:04 +05:30
Nabin Hait
beb2f3c415 Merge branch 'creamdory-sort_bom_items' into develop 2017-09-14 13:23:37 +05:30
Nabin Hait
77b225e021 Fetch BOM items in Production Order in the same order as BOM 2017-09-14 13:22:45 +05:30
Nabin Hait
3f583b6dd2 Merge branch 'sort_bom_items' of https://github.com/creamdory/erpnext into creamdory-sort_bom_items 2017-09-14 12:59:31 +05:30
Vishal Dhayagude
d3e22ac09e [UI Test] Modified Sales Order UI Test (#10770)
* [UI Test] Modified Sales Order UI Test

* [fix] Codacy fixed
2017-09-14 12:51:22 +05:30
Nabin Hait
f6b132f78e Update test_quotation.js 2017-09-14 11:55:31 +05:30
Nabin Hait
c7c141a5a0 Update test_setup_wizard.py 2017-09-14 11:51:43 +05:30
rohitwaghchaure
f8458ed9e4 Merge pull request #10771 from nabinhait/pro_order_99
Update actual dates in Production Order from Timesheet
2017-09-14 10:53:48 +05:30
rohitwaghchaure
9a0db392de [Fix] Only typed keywords displying in the field on selection of customer (#10778) 2017-09-14 10:51:21 +05:30
Nabin Hait
92309afea1 Update test_setup_wizard.py 2017-09-13 22:37:14 +05:30
Prateeksha Singh
242218d2b7 Progress fixes (#10710)
* [progress] sales target slide

* [fix] rerun patch for sales target slide
2017-09-13 18:41:01 +05:30
tundebabzy
c050c6945c show error message if cannot get accounts details (#10768) 2017-09-13 15:27:30 +05:30
Vishal Dhayagude
52ac483368 [NEW] Travis Parallel Test (#10755)
* test

* test2

* test travis
2017-09-13 15:18:41 +05:30
Nabin Hait
c443c9f05d Update actual dates in Production Order from Timesheet 2017-09-13 15:14:40 +05:30
Nabin Hait
78baebfe0d Setup wizard test fix 2017-09-13 15:12:45 +05:30
Rushabh Mehta
f056974bc5 [domain] Healthcare (#10664)
* Medical module for erpnext

* Changes in core for Medical module

* patient registration updated

* fix - appointment invioce - fields missing

* pages- indicator instead of bg-color

* Lab Test field renamed service type

* Department added Lab Test

* procedure name in prescription

* fixes sample collection

* filter disabled patient

* fix patient admission

* updated patient age

* availability check msg updated

* fixes, removed procedure from invoice

* sample print renamed

* fixes, validation

* service desk physician in filter

* refactor scheduler

* Appointment -field property - set only once = 1

* Appointment - Mark closed and pending buttons removed

* Appointment - readonly = 1 if value set

* Appointment - availabilty

* Appointment - Cancel - info - cancel invoice

* Appointment - set pending appointments

* Dosage form - new DT

* Drug Prescription - Dosage form added

* Facility - Floor - removed from Fecility

* Floor - removed

* Lab Test Template - item creation validation

* Procedure - Create Procedure

* Procedure Appointment - new DT

* Service Unit - Floor reference removed

* Zone Fcilities - Unused DT removed

* Appointment Desk - fixed

* Service Desk - method pointing from procedure changed to procedure_appointment

* Consultation print - got featured

* Consultation - removed patient refernce to procedure prescription

* Procedure Prescription - removed patient refernce

* Lab Test - Changed field properties and value

* Lab Test - field property changed

* Lab Test - methods rewrite - lab test doc creation

* Lab Test - create lab test from invoice and consultaion - got changed

* Button History changed to Medical Record

* Service Desk - Updated

* Notification - Procedure Appointment

* fix-get procedure prescription

* fix field added to test prescription

* msgprint on invoice creation

* fix data on install

* Merge branch erpnext/develop

* fixes- minor

* Setup wizard - Create Sensitivity

* Appointment - Validate and Save if there is no schedule for Physician

* Consultation - Button create vital signs and medical record

* Review Type - New DocType

* Review Detail and Treatment Plan - Childs - Consultation

* Patient Medical Record - field Attach doc

* Consultation - New Fields

* Consultation - Manage new Fields - Medical record add action

* Patient Relation - Child DocType - Patient

* Patient - Patient Relation added

* Patient - collapsible = 1

* Laboratory Settings - fields - message for lab test

* Laboratory Settings - get message for lab test

* SMS text for lab test and invoice test report

* Procedure Stock Detail - Stock detail for Procedure and Template

* Template Stage Detail - Stage detail for Procedure Template

* Procedure Stage Detail - Stage detail for Procedure

* Service Unit - field - warehouse

* Scheduler - msg - content changed

* Laboratory Settings - defualt - msg content

* Invoice Test Report - msg print

* Print Format-Changed-Consultation-Invoice Test Report-Lab Test

* OP Settings - Expnse Account for Stock Entry in Procedure

* Procedure and Procedure Template - Manage Stock Stage and Sample Collection

* Procedure Appointment - Manage Stock and Stage

* Lab Test - fixed - resource not find

* Invoice Test Report - fixed - resource not find

* Procedure - doc reload after insert

* Patient Medical Record - fixed - refernce missed

* Create Vital Signs -on client side

* Rename module Medical to Healthcare

* Remove In Patient (IP) Feature.

* Rename - Procedure to Clinical Procedure

* Remove spaces in Naming Series

* Rename Duration to Drug Prescription Duration

* Duration to Drug Prescription Duration

* Merge All Settings to Healthcare Settings

* Healthcare settings - import fixed

* Procedure related documents are removed

* Appointment Desk and Sevrvice Desk are removed

* Consultation - minimal

* Consultation - minimal

* Consultation - minimal - patient detials in collapsible section

* Message Print to Alerts

* Patient - some fields removed

* Patient - create consultation - message print to alerts

* Consultation - show patient details updated

* Setup wizard - Duration to Drug Prescritpion Duration

* Healthcare Settings - patient registration - fee collection

* Lab Test - Create Sales Invoice bug fixed

* Healthcare menu rearranged

* Healthcare Settings - Optimised and Rearragnged

* Healthcare Settings - Expense account removed

* Receivable account removed from patient

* Patient - Optimised and Rearragnged

* Removed Referring Physician

* Healthcare Settings - bold headings removed

* Physician - Patient - Fields are Segregated

* Remove Service Unit

* Remove - Service Type

* Consultation invoice

* Lab Test - invoice

* Patient - Invoice

* Rename Appointment to Patient Appointment

* wip

* Patient Dashboard, Physician Form cleanup

* Dosage renamed to Prescription Dosage

* Renamed Drug Prescription Duration to Prescription Duration

* Patient Appointment booking modal

* Patient Age - calculate by dob

* Remove - scheduler

* Consultation - Appointment to Patient Appointment

* Patient Dashboard - rearranged

* Patient Appointment

* Removed rer_physician from lab test and consultation

* Patient Appontment Changes

* Appointment and Consultation - optimized

* Patient Appointment - fee validity code optimized

* Consultation and Patient Appointment - Invoice validate two side

* fix: #13 remove relation to admission

* Healthcare - Patient Portal

* fix import error

* domain Healthcare added on install

* Removed - Invoice Test Report

* Physician Schedule - menu

* Consultation - patient details - re write

* New Doctype-Medical Code

* Consultation - Daignosis codification

* Medical Code - Codification - Settings

* Medical Code Standard - Medical Code - Codification - Settings

* fix appointment calendar

* fix appointment analytics

* Menu Medical Code Standard

* New Doctype - Medical Code Standard

* Set Physician Role insted of IP Physician and OP Physician Role

* fixed some json files

* Medical code - permission to physician

* Unused Childs - Work Schedule and User List - Removed

* Label Procedure to Lab Test

* Lab Test and Patient - code optimised

* Add Item Groups - setup wizard

* Healthcare Settings - add Role - Medical Administrator

* Healthcare - Demo setup - Make Demo

* Fee Validity - Logic Test

* Test Fee Validity - Optimised

* Healthcare Doctypes - Restricted to Domain Healthcare

* Domainify - remove Healthcare Roles - Other Domains

* Healthcare doctypes - beta checked

* Codacy fixes

* Codacy - fixes

* Codacy - fixes

* Codacy - fixes

* Codacy - fixes

* Codacy - fixes

* Lab Test - print hide =1 for some fields

* Consultation - Codification field label to Medical Coding

* Codacy fixes - import frappe and etc.

* Codacy fixes - import frappe in test_vital_signs

* Codacy fixes

* Codacy fixes

* Codacy fixes and remove delete perm for patient

* send_sms - import form frappe

* Healthcare Settings

* Lab Prescription - Consultation - Test Code - read_only = 0

* Portal fixes

* Patient Appointment - filter physician - if has schedule

* Physician - IP Charge - Removed

* test - files

* Web Form - Patient Profile - removed

* Role Medical Administrator to Healthcare Administrator

* WIP healthcare documentation

* Coday - fixes

* Travis - fixes

* Lab Test Report - menu

* Reorder Healthcare settings - group lab config to bottom

* Sample Collection - New - allow Sample and patient Selection

* Rate - similar behaviour and Label as in Item Standard Selling Rate

* Healthcare documentation

* Lab Test Samples to Lab Test sample

* Commplaints to Complaint

* Commplaints to Complaint

* Antibiotics to Antibiotic

* Appointment Token Number - remove

* View - Medical record

* Codacy fixes

* update healthcare docs

* Cleanup Docs - Search, quick entry, trsck change, etc.

* [minor] ux changes
2017-09-13 12:52:30 +05:30
Nabin Hait
ff667695ad timeout in setup wizard test 2017-09-13 11:26:55 +05:30
Rushabh Mehta
f849915c13 [fix] label 2017-09-13 10:48:53 +05:30
Nabin Hait
231c324589 Merge branch 'master' into staging 2017-09-12 16:26:31 +05:30
Nabin Hait
f8f29677fd Merge branch 'master' into develop 2017-09-12 16:16:57 +05:30
Nabin Hait
50312b54a0 Merge branch 'hotfix' 2017-09-12 16:16:55 +05:30
Nabin Hait
e47bd4f477 bumped to version 8.11.2 2017-09-12 16:46:55 +06:00
rohitwaghchaure
ab64e323cd Merge pull request #10747 from mbauskar/pos
rename Is Online field to Use POS in Offline Mode in pos settings
2017-09-12 16:14:28 +05:30
rohitwaghchaure
67dfd26639 [fix] Production planning tool, unable to download material required report (#10704) 2017-09-12 15:54:27 +05:30
rohitwaghchaure
54099e592e [fix] Serial No has already been received error while making purchase receipt entry for the returned serial no (#10736) 2017-09-12 15:51:52 +05:30
Manas Solanki
580f39a12c check the instructor table before querying (#10754) 2017-09-12 15:49:36 +05:30
Nabin Hait
c9e96c15af Rate and amount in a single row in tax breakup 2017-09-12 15:45:49 +05:30
Nabin Hait
de9eebe51c Fixed multiple ui tests 2017-09-12 15:40:33 +05:30
Sagar Vora
d54d6bc572 [fix] use stock_qty in reports instead of qty to match with stock_uom (#10727) 2017-09-12 11:31:10 +05:30
rohitwaghchaure
38830e54d8 [fix] No module namd student_batch_name.student_batch_name error in the patch (#10745) 2017-09-12 11:25:02 +05:30
Rohit Waghchaure
1a77922e85 rename Is Online field to Use POS in Offline Mode in pos settings 2017-09-12 11:01:48 +05:30
Makarand Bauskar
d0823adf42 [minor] translate the action name in get_slide_settings (#10740) 2017-09-12 10:52:24 +05:30
rohitwaghchaure
80b902cea6 Merge pull request #10732 from rohitwaghchaure/rename_pos_field_in_pos_settings
Rename Is Online field to Use POS in Offline Mode in pos settings
2017-09-11 22:36:38 +05:30
Nabin Hait
e5716e3b1e Default view of BOM is Listview 2017-09-11 19:21:47 +05:30
rohitwaghchaure
47605cae16 Merge pull request #10737 from nabinhait/budget_variance_for_project
[fix] Actual amount for budget variance report
2017-09-11 16:47:16 +05:30
Frappe PR Bot
8a803a2310 [Translation] Updated Translations (#10741) 2017-09-11 16:31:10 +05:30
rohitwaghchaure
e2149cb46f Merge pull request #10697 from rohitwaghchaure/customer_search_optimization
[Fix] Customer search optimization for the offline POS
2017-09-11 16:23:15 +05:30
Nabin Hait
509bca36b1 Reverse charge in gst print format 2017-09-11 15:19:07 +05:30
Nabin Hait
cfb9310d13 Removed commit after creating custom gst fields 2017-09-11 15:00:16 +05:30
Rohit Waghchaure
4e006b0bc5 rename Is Online field to Use POS in Offline Mode in pos settings 2017-09-11 14:51:50 +05:30
Nabin Hait
f5cbb9c7b9 [fix] Actual amount for budget variance report 2017-09-11 13:58:15 +05:30
mbauskar
336c9b23d6 Merge branch 'master' into staging 2017-09-10 12:32:21 +05:30
mbauskar
dfeadf876e Merge branch 'master' into develop 2017-09-10 12:32:21 +05:30
mbauskar
b9d158076e Merge branch 'hotfix' 2017-09-10 12:32:20 +05:30
mbauskar
438088f69d bumped to version 8.11.1 2017-09-10 13:02:20 +06:00
Makarand Bauskar
80b2ba2b9a [hotfix] fixed Not Permitted issue for System user while accessing documents on portal (#10725)
* [hotfix] dont allow guest user to list the invoices or orders

* [hotfix] fixed Not Permitted issue for System user while accessing documents on portal

* [codecy] removed trailing whitespace

* [fixes] added filters for supplier in RFQ and other minor fixes
2017-09-10 12:04:28 +05:30
Faris Ansari
197901108e Merge pull request #10713 from mbauskar/hotfix
[fix] Tax area alignment (#10690)
2017-09-08 15:59:19 +05:30
Faris Ansari
425f1df799 [fix] Tax area alignment (#10690) 2017-09-08 15:56:34 +05:30
mbauskar
9bc2b66e14 Merge branch 'develop' into staging 2017-09-07 21:08:26 +05:30
Nabin Hait
d4e57a38a4 Fixed multiple ui test cases 2017-09-07 19:16:38 +05:30
Rohit Waghchaure
06b22e9ac1 [Fix] Customer search optimization for the offline POS 2017-09-07 17:44:42 +05:30
rohitwaghchaure
07b713121b Merge pull request #10600 from netchampfaris/pos-refactor
POS Online
2017-09-07 17:39:45 +05:30
rohitwaghchaure
1b65575860 Merge branch 'develop' into pos-refactor 2017-09-07 17:15:58 +05:30
rohitwaghchaure
166b78f022 [Enhance] Subscription module (#10089)
* [Enhance] Subscription module

* Added view documents from the subscription form

* Test cases

* documentation

* UI Test cases, fixes

* Removed child table in the subscription

* Provision to make subscription from the document, added subscription in the dashboard for the sales and buying flow

* added patch to make subscription from the recurring data

* Rename field subscriptio to subscription_id, added new test cases, remove recurring_document from controller

* renamed subscription_id to subscription
2017-09-07 16:14:22 +05:30
Vishal Dhayagude
c79d14190f [fix] travis failed (#10702) 2017-09-07 16:05:41 +05:30
Rushabh Mehta
2e8e5354e9 [fix] trainig_feedback.py 2017-09-07 10:43:36 +05:30
Rushabh Mehta
290e066633 [rename] /test_training_event_attendance.js 2017-09-07 09:07:15 +05:30
Rushabh Mehta
134d59949a [minor] update warehouse_group in item.reorder_levels 2017-09-07 09:04:24 +05:30
Prateeksha Singh
2697e332f3 [fix] wizard UI test order (#10663)
* [fix] wizard ui test order

* [setup] remove old test

* [fix] commit to remove lock from defaults table during setup
2017-09-07 09:03:16 +05:30
Rohit Waghchaure
c72d08e8b9 Added indicator to show stock is available or not 2017-09-06 14:56:08 +05:30
rohitwaghchaure
ec46e51ed4 Merge pull request #10426 from nabinhait/payment_entry_deductions
Unallocated and difference amount calculation in Payment Entry
2017-09-06 13:04:25 +05:30
Rohit Waghchaure
7419c4b577 Fixed test cases 2017-09-06 12:44:51 +05:30
rohitwaghchaure
914fd197fc Update test_payment_against_invoice.js 2017-09-06 12:42:58 +05:30
Faris Ansari
8868ae22be [fix] Tax area alignment (#10690) 2017-09-06 12:17:12 +05:30
Nabin Hait
ded8d11728 Js tests added for write off difference amount 2017-09-06 12:11:48 +05:30
Nabin Hait
6c3618be37 Unallocated and difference amount calculation in Payment Entry 2017-09-06 12:10:52 +05:30
Rushabh Mehta
6ef741554c [fix] [patch] rename_company_sales_target_field.py 2017-09-06 10:53:26 +05:30
mbauskar
668d04548a Merge branch 'master' into develop 2017-09-05 20:45:00 +05:30
mbauskar
68a4146999 Merge branch 'staging' 2017-09-05 20:44:59 +05:30
mbauskar
d4316f0264 bumped to version 8.11.0 2017-09-05 21:14:58 +06:00
Faris Ansari
4bcaeb312c fix codacy 2017-09-05 17:30:22 +05:30
Faris Ansari
e4434d3200 Merge branch 'develop' into pos-refactor 2017-09-05 17:18:04 +05:30
Faris Ansari
62b1dc777e Namespace PointOfSale class 2017-09-05 17:10:24 +05:30
Nabin Hait
799619b6b0 Fixed multiple uom in selling 2017-09-05 15:52:12 +05:30
Makarand Bauskar
3ad045302b [minor] set abbreviation on company name trigger (#10671)
* [minor] set abbreviation on company name trigger

* [minor] codecy fixes
2017-09-05 15:23:55 +05:30
Nabin Hait
499fbe90dc Test case fixed for multi-currency and multi-uom BOM (#10679) 2017-09-05 15:16:32 +05:30
Francisco Roldán
c929e88b97 Company Dashboard Title Translatable (#10673) 2017-09-05 15:09:35 +05:30
creamdory
05885ca184 Sorting in Production Order BOM Items 2017-09-05 17:02:54 +08:00
Rohit Waghchaure
2967d7ed01 Merge branch 'bom_currency' into develop 2017-09-05 11:26:22 +05:30
Rohit Waghchaure
c872095d76 update rate based on uom conversion factor 2017-09-05 11:25:05 +05:30
Frappe PR Bot
8054d962cf [Translation] Updated Translations (#10669) 2017-09-05 09:19:06 +05:30
Nabin Hait
22cff25bf5 BOM rates as per selected currency and UOM 2017-09-04 18:31:45 +05:30
mbauskar
7faac85fff Merge branch 'master' into staging 2017-09-04 14:50:32 +05:30
mbauskar
d32f08f6ec Merge branch 'master' into develop 2017-09-04 14:50:31 +05:30
mbauskar
10fdf5a8c3 Merge branch 'hotfix' 2017-09-04 14:50:30 +05:30
mbauskar
11cf44986b bumped to version 8.10.2 2017-09-04 15:20:30 +06:00
Prateeksha Singh
95d8fd38f5 User Progress (#10336)
* [user-progress] first cut

* [user-progress] Add users slide, remove taxes, make sample data

* wip tests

* [setup-wiz] UI test

* [user-progress] notif test, docs trim

* wip

* [user-progress] Setup Progress single to update action states, fixtures

* setup progress actions patch

* rename sales_target field patch

* [progress] wip reform slide data

* [progress] remove slide data

* [setup] add roles for GST doctypes, remove commit from fixtures
2017-09-04 11:14:04 +05:30
Makarand Bauskar
cf9e986f82 [hotfix] fixed the invalid variable name lead.name (#10648) 2017-09-04 10:25:37 +05:30
rohitwaghchaure
fd39d6bd3c [Enahance] Provision to select customer, item code while making an invoice from timesheet (#10616) 2017-09-04 10:20:40 +05:30
Arundhatii
2e6db4d928 Help pages for Attendance (#10634)
* Help pages for Schools setup

* Documentation of Schools module

* Help pages for Student

* Help pages for Student

* Help pages for Schools Student and Admission Module

* Documentation for Schools Attendance
2017-09-04 10:17:18 +05:30
Saurabh
21833413b0 [fix] ERPNext signup link fix on demo page (#10649) 2017-09-04 10:15:24 +05:30
Francisco Roldán
11355cd3c9 Set at lost translated in quotation (#10652) 2017-09-04 10:14:58 +05:30
Nabin Hait
2b05e61d58 Merge branch 'rmehta-bcornwellmott-confirm_training' into develop 2017-09-04 10:13:47 +05:30
Nabin Hait
baacf51a00 Fixed merge conflict 2017-09-04 10:13:29 +05:30
Zarrar
85eeafdccc added filter for grading scale selection (#10639) 2017-09-01 21:45:10 +05:30
Makarand Bauskar
d6922b2de3 [hotfix] lead name should available before creating new customer from quotations (#10642) 2017-09-01 18:45:40 +05:30
Rohit Waghchaure
6ab630371d Fixed serial no trigger not working from dialog box 2017-09-01 17:02:42 +05:30
Umair Sayed
f1881065a8 Merging Help Articles (Q & A) into Manual (Part 2) (#10629)
* adding articles in the manual

* adding articles in the manual 2

* migrating help articles to manuals

* migrating help articles to manuals
2017-09-01 16:26:41 +05:30
Rushabh Mehta
fc1c00716c [test] test_account.js - more timeout? 2017-09-01 12:41:12 +05:30
Rushabh Mehta
baabb07e00 [test] test_account.js 2017-09-01 12:12:39 +05:30
Rushabh Mehta
7d868e41a6 [test] test_account.js 2017-09-01 11:46:11 +05:30
Nabin Hait
a9c9b69c22 Change actual charges based on exchange rate (#10619)
* Change actual charges based on exchange rate

* Update transaction.js
2017-08-31 19:40:09 +05:30
Frappe PR Bot
d112ee5244 [Translation] Updated Translations (#10628) 2017-08-31 19:38:41 +05:30
Rohit Waghchaure
3e43927767 Test cases 2017-08-31 18:21:27 +05:30
Saurabh
60739847ab [minor][fix] change price field type from float to currency (#10626) 2017-08-31 17:08:30 +05:30
mbauskar
9012a9b414 Merge branch 'master' into staging 2017-08-31 15:31:48 +05:30
mbauskar
4f939b82b6 Merge branch 'hotfix' 2017-08-31 15:31:47 +05:30
mbauskar
2965f92be3 Merge branch 'master' into develop 2017-08-31 15:31:47 +05:30
mbauskar
2a4328b4f5 bumped to version 8.10.1 2017-08-31 16:01:47 +06:00
mbauskar
d974bcd2fa Merge branch 'develop' into staging 2017-08-31 15:30:12 +05:30
Nabin Hait
d7ff9dca1d Fixed rounding issue in Process Payroll, fixes #9300 (#10586) 2017-08-31 15:17:01 +05:30
Nabin Hait
e7e29b7f10 GST print format for POS (#10590)
* Serial no added in GST tax invoice

* GST print format for POS
2017-08-31 15:06:12 +05:30
Umair Sayed
84be137b4e Migrating Help Articles (Q&A format) into User Manual (#10608)
* adding articles in the manual

* adding articles in the manual 2

* migrating help articles to manuals
2017-08-31 14:53:47 +05:30
Vishal Dhayagude
1252c30edf [UI Test] UI test for Repack and Sales Invoice with Serialize item Added (#10583)
* [UI Test] UI test for Repack and Sales Invoice with Serialize item Added

* [Fix] Fixed path for sales invoice"
2017-08-31 14:47:56 +05:30
Vishal Dhayagude
1458d7fea6 [UI Test] Stock Entry for material issue with serialize item (#10592) 2017-08-31 14:47:01 +05:30
tundebabzy
7f8a259beb Fixer Always Fetches Latest Exchange Rate Even When Date is Specified (#10596) (#10597)
* test that confirms the bug. Same test should pass after fix

* make use of correct api url
2017-08-31 14:30:15 +05:30
rohitwaghchaure
56e31d05e9 [Fix] POS customer field is hang while searching customer, make error log if sync has failed (#10607) 2017-08-31 14:19:58 +05:30
krnkris
3c635e219e Rename fr_plan_comptable_général.json to fr_plan_comptable_general.json (#10601) 2017-08-31 14:17:46 +05:30
Makarand Bauskar
de278635a3 [hotfix] fixes for UnicodeDecodeError (#10620) 2017-08-31 13:36:56 +05:30
Rohit Waghchaure
7e752c4ebf Added patch, fixed codacy issue 2017-08-31 00:31:35 +05:30
Faris Ansari
6163a397df Disable eslint in lib 2017-08-30 12:54:16 +05:30
Faris Ansari
1116f96aee Grand Total Value width 2017-08-30 12:53:08 +05:30
Faris Ansari
491108a198 Merge branch 'develop' into pos-refactor 2017-08-30 12:37:05 +05:30
mbauskar
5096c45dec Merge branch 'master' into hotfix 2017-08-29 20:42:06 +05:30
mbauskar
a896e52489 resolved merge conflicts 2017-08-29 20:41:59 +05:30
Rohit Waghchaure
70aaff46be minor fix in item group search 2017-08-29 19:19:58 +05:30
tundebabzy
1a947dbf6a Item Name not loaded in Material Request via BOM (#10535) (#10555)
* adds item_name to child table

* adds two new functions to utils:
- first_row_is_empty: to check if first row in child table is empty
- remove_empty_first_row: to remove the empty first row in a child table

* removes empty first row after getting from BOM

* ui test
2017-08-29 18:18:27 +05:30
Faris Ansari
c70bbacd34 Add online, offline option, fix search 2017-08-29 15:27:17 +05:30
Faris Ansari
655f86d5e2 UI fixes 2017-08-29 14:27:01 +05:30
Faris Ansari
b9939a6449 Merge pull request #10448 from joelios/selfpostback
improvement for self-postbacks
2017-08-29 14:05:13 +05:30
Faris Ansari
6f50b3a5b2 handle both cases 2017-08-29 14:02:49 +05:30
Rohit Waghchaure
ba3f0e6b70 Added serial no, batch no, item group functionality 2017-08-28 19:45:58 +05:30
Aditya Hase
6ccb6562f1 Python 3 compatibility syntax error fixes (#10519)
* Use Python 3 style print function

* Use 'Exception as e' instead of 'Exception, e'

* Unpack tuple arguments explicitly in instead of relying on auto unpacking

* Use consistent indentation

* Use 0 if stock_frozen_upto_days is None
2017-08-28 18:17:36 +05:30
Faris Ansari
847f9f80c1 Merge pull request #10559 from mntechnique/pos_scanner_hotfix
[Fix] POS Scanner
2017-08-28 16:54:01 +05:30
Vishal Dhayagude
7ed4bfe7ee [UI Test] UI Test for Material Receipt with Serialize Item Added (#10565)
* [UI Test] UI Test for Material Receipt with Serialize Item Added

* [fix]Codacy fixed
2017-08-28 16:53:25 +05:30
Faris Ansari
8fbc08f91f Decrease timeout to 400 2017-08-28 16:52:20 +05:30
Vishal Dhayagude
872bebbbf8 [UI Test] Stock Entry for Subcontract (#10574) 2017-08-28 15:33:21 +05:30
Vishal Dhayagude
f8e6c44996 [UI Test] Stock Entry for Material Transfer to Manufacture (#10572) 2017-08-28 15:32:33 +05:30
mbauskar
aaec42ebc2 resolved merged conflicts 2017-08-28 11:57:56 +05:30
Vishal Dhayagude
914b8463b7 [UI Test] UI Test for Payment Request Added: (#10553) 2017-08-28 11:14:28 +05:30
Utkarsh Goswami
7ba2a83182 Tests for Loan (#10557) 2017-08-28 11:13:16 +05:30
Vishal Dhayagude
554cf9be44 [UI Test] UI Test Added for Bank Reconciliation (#10563) 2017-08-28 11:11:36 +05:30
Vishal Dhayagude
da2164373c [UI Test] UI Test added for Batch (#10564) 2017-08-28 11:10:26 +05:30
Vishal Dhayagude
c3a2204653 [UI Test] UI Test for Sales Order Cancel, amend and save (#10570) 2017-08-28 11:09:35 +05:30
Faris Ansari
3ae9e91bcd Add memoization in search 2017-08-27 14:04:23 +05:30
Faris Ansari
d733b7d7d0 Styling and code fixes 2017-08-27 13:56:33 +05:30
Rohit Waghchaure
5e2d2059fe Added email, edit on form view from POS, pay using numpad functionality 2017-08-27 08:54:40 +05:30
Revant Nandgaonkar
2558daf6b7 Allow search without keypress enter 2017-08-26 15:52:35 +05:30
Revant Nandgaonkar
2f7cb82ca0 [Fix] POS Scanner
Search item based on key press instead of 1sec wait
Fast Scanning needs this to avoid 1sec delay
2017-08-26 09:58:15 +05:30
Zarrar
7dc113e977 instructor-naming (#10550) 2017-08-25 17:48:36 +05:30
Utkarsh Goswami
579c8e68f9 Tests for Expense Claims [HR] (#10514) 2017-08-25 16:12:49 +05:30
Ashwini Save
e33a1e0515 Hide "Help Article" button for timeline Communication type "Comment". (#10541) 2017-08-25 12:44:33 +05:30
Nabin Hait
bf4a974124 IMproved print format for AR/AP report (#10528) 2017-08-25 12:10:49 +05:30
Utkarsh Goswami
9a04da27b0 Test for training (#10545) 2017-08-25 12:01:04 +05:30
AravindPranera
764bb30d2d Fetching Opportunity items into Request for Quotation 2017-08-24 18:34:45 +05:30
AravindPranera
6544a85f1e Opportunity Items fetching into Request for quotation 2017-08-24 18:32:40 +05:30
Manas Solanki
8de7c0245c Fixes in the naming series (#10480)
* rewrite the js

* fix the space issue in the naming series
2017-08-24 17:51:23 +05:30
Vishal Dhayagude
17b2720f5b [UI Test] UI Test for Payment Entry (#10521) 2017-08-24 17:50:28 +05:30
Faris Ansari
5d9196960e new form improvements 2017-08-24 17:09:34 +05:30
Zarrar
1010a2a2a4 Resolving some issues in school [ issue no:- #10464 ] (#10529)
* guardian_name issue fix

* guardian table issue resolved

* resolved fetching issue + unnecessary code removed
2017-08-24 16:22:06 +05:30
Utkarsh Goswami
3da5574d79 Test for appraisal (#10525) 2017-08-24 15:48:57 +05:30
Rohit Waghchaure
e5f6b4d640 Added print, make new invoice from POS functionality 2017-08-24 15:27:55 +05:30
Rushabh Mehta
72fa958f2c [layout] lead and opportunity (#10487) 2017-08-23 18:47:57 +05:30
Vishal Dhayagude
641d88fd6b [UI Test] UI Test added for Journal Entry (#10512)
* [UI Test] UI Test added for Journal Entry

* [mod] Edited date in journal Entry

* [fix] Codacy fixed
2017-08-23 18:32:12 +05:30
Faris Ansari
6d2f6c2e4d Search improved, code refactor 2017-08-23 16:25:16 +05:30
Rushabh Mehta
4a546e6c18 [minor] delivery note standard filter 2017-08-23 16:16:43 +05:30
Faris Ansari
26df5b8c00 Connect Numpad events with POSCart 2017-08-23 13:12:12 +05:30
Rohit Waghchaure
b73321c577 Item search refactor 2017-08-23 12:15:10 +05:30
Faris Ansari
78c81d9c6c Refactor payment code 2017-08-21 15:05:33 +05:30
Faris Ansari
eba50c6860 Merge branch 'pos-refactor' of https://github.com/netchampfaris/erpnext into pos-refactor 2017-08-18 17:00:02 +05:30
Rohit Waghchaure
f03a73466c Added modal for multi mode payment, provision to add write off and change amount 2017-08-18 12:15:19 +05:30
Joel Mesmer
97c1bcf14f improvement for self-postbacks 2017-08-17 22:20:18 +02:00
Faris Ansari
0f3d431476 Update cart ui from cur_frm, Add number pad 2017-08-17 12:56:14 +05:30
Rohit Waghchaure
b1daab4284 Added functional part 2017-08-17 12:56:14 +05:30
Faris Ansari
7bcb1cfc42 more styling 2017-08-17 12:56:14 +05:30
Faris Ansari
a0f8687945 Styling for search fields 2017-08-17 12:56:14 +05:30
Faris Ansari
03e7ec29e7 Add clusterize, move customer field to POSCart, get POS profile 2017-08-17 12:56:14 +05:30
Faris Ansari
6e7db034f2 [wip] New POS UI 2017-08-17 12:56:14 +05:30
Faris Ansari
21fc26c2a2 Update cart ui from cur_frm, Add number pad 2017-08-14 18:25:59 +05:30
Rushabh Mehta
4f366e9c38 [fix] conflicts 2017-08-14 16:15:20 +05:30
Rushabh Mehta
683b015951 [fix] email alert 2017-08-14 15:03:33 +05:30
Rushabh Mehta
1132502e14 [fix] test 2017-08-14 12:09:30 +05:30
Rushabh Mehta
ea573e2421 [training] update names 2017-08-14 11:53:34 +05:30
Rushabh Mehta
1fe1a47658 [docs] update docs 2017-08-14 11:53:34 +05:30
Rushabh Mehta
6cb14cfc04 [docs] update docs 2017-08-14 11:53:34 +05:30
Rushabh Mehta
89505522d3 [docs] update docs 2017-08-14 11:53:34 +05:30
Rushabh Mehta
550b0fab84 [fixes] email notifications by email alert on training event and result 2017-08-14 11:53:34 +05:30
Ben Cornwell-Mott
35a4e587ee Fixes for camel_case and translations 2017-08-14 11:53:34 +05:30
Ben Cornwell-Mott
e92b4737e3 codacy fixes 2017-08-14 11:53:34 +05:30
Ben Cornwell-Mott
94c6b7409b Updated documentation 2017-08-14 11:53:34 +05:30
Ben Cornwell-Mott
e9dbafcc10 Improve email format for training event, add ui test 2017-08-14 11:53:34 +05:30
Rohit Waghchaure
854d335ab1 Added functional part 2017-08-14 11:34:42 +05:30
Faris Ansari
5a13087939 more styling 2017-08-11 15:49:23 +05:30
Faris Ansari
f7c7ff4aae Styling for search fields 2017-08-10 18:28:05 +05:30
Faris Ansari
65c4bd6db6 Add clusterize, move customer field to POSCart, get POS profile 2017-08-10 17:17:49 +05:30
Faris Ansari
519cc09979 [wip] New POS UI 2017-08-10 17:17:49 +05:30
1177 changed files with 146714 additions and 61258 deletions

View File

@@ -51,11 +51,17 @@ before_script:
- bench start &
- sleep 10
script:
- set -e
- bench run-tests
- sleep 5
- bench reinstall --yes
- bench execute erpnext.setup.setup_wizard.utils.complete
- bench execute erpnext.setup.utils.enable_all_roles_and_domains
- bench run-ui-tests --app erpnext
jobs:
include:
- stage: test
script:
- set -e
- bench run-tests
env: Server Side Test
- # stage
script:
- bench --verbose run-setup-wizard-ui-test
- bench execute erpnext.setup.utils.enable_all_roles_and_domains
- bench run-ui-tests --app erpnext
env: Client Side Test

View File

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

View File

@@ -78,6 +78,7 @@ def get_chart(chart_template, existing_company=None):
for folder in folders:
path = os.path.join(os.path.dirname(__file__), folder)
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
chart = f.read()
@@ -105,6 +106,7 @@ def get_charts_for_country(country):
path = os.path.join(os.path.dirname(__file__), folder)
for fname in os.listdir(path):
fname = frappe.as_unicode(fname)
if (fname.startswith(country_code) or fname.startswith(country)) and fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
_get_chart_name(f.read())

View File

@@ -4,7 +4,7 @@
"""
Import chart of accounts from OpenERP sources
"""
from __future__ import unicode_literals
from __future__ import print_function, unicode_literals
import os, json
import ast
@@ -229,7 +229,7 @@ def make_charts():
filename = src["id"][5:] + "_" + chart_id
print "building " + filename
print("building " + filename)
chart = {}
chart["name"] = src["name"]
chart["country_code"] = src["id"][5:]

View File

@@ -851,7 +851,7 @@
"4457-Taxes sur le chiffre d'affaires collect\u00e9es par l'entreprise": {
"44571-TVA collect\u00e9e": {
"account_type": "Tax",
"tax_rate": 20.0
"is_group": 1
},
"44578-Taxes assimil\u00e9es \u00e0 la TVA": {}
},
@@ -1607,4 +1607,4 @@
"root_type": "Income"
}
}
}
}

View File

@@ -5,7 +5,9 @@ QUnit.test("test account", function(assert) {
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('Tree', 'Account'),
() => frappe.timeout(3),
() => frappe.click_button('Expand All'),
() => frappe.timeout(1),
() => frappe.click_link('Debtors'),
() => frappe.click_button('Edit'),
() => frappe.timeout(1),

View File

@@ -286,6 +286,99 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "currency_exchange_section",
"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": "Currency Exchange Settings",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "allow_stale",
"fieldtype": "Check",
"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": "Allow Stale Exchange Rates",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"depends_on": "eval:doc.allow_stale==0",
"fieldname": "stale_days",
"fieldtype": "Int",
"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": "Stale Days",
"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,
"unique": 0
}
],
"has_web_view": 0,
@@ -299,7 +392,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-16 17:39:50.614522",
"modified": "2017-09-05 10:10:03.117505",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -324,6 +417,46 @@
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Purchase User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"quick_entry": 1,
@@ -333,4 +466,4 @@
"sort_order": "ASC",
"track_changes": 1,
"track_seen": 0
}
}

View File

@@ -5,10 +5,20 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, comma_and
from frappe.utils import cint
from frappe.model.document import Document
class AccountsSettings(Document):
def on_update(self):
pass
pass
def validate(self):
self.validate_stale_days()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
frappe.msgprint(
"Stale Days should start from 1.", title='Error', indicator='red',
raise_exception=1)

View File

@@ -0,0 +1,35 @@
QUnit.module('accounts');
QUnit.test("test: Accounts Settings doesn't allow negatives", function (assert) {
let done = assert.async();
assert.expect(2);
frappe.run_serially([
() => frappe.set_route('Form', 'Accounts Settings', 'Accounts Settings'),
() => frappe.timeout(2),
() => unchecked_if_checked(cur_frm, 'Allow Stale Exchange Rates', frappe.click_check),
() => cur_frm.set_value('stale_days', 0),
() => frappe.click_button('Save'),
() => frappe.timeout(2),
() => {
assert.ok(cur_dialog);
},
() => frappe.click_button('Close'),
() => cur_frm.set_value('stale_days', -1),
() => frappe.click_button('Save'),
() => frappe.timeout(2),
() => {
assert.ok(cur_dialog);
},
() => frappe.click_button('Close'),
() => done()
]);
});
const unchecked_if_checked = function(frm, field_name, fn){
if (frm.doc.allow_stale) {
return fn(field_name);
}
};

View File

@@ -0,0 +1,22 @@
import unittest
import frappe
class TestAccountsSettings(unittest.TestCase):
def tearDown(self):
# Just in case `save` method succeeds, we need to take things back to default so that other tests
# don't break
cur_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
cur_settings.allow_stale = 1
cur_settings.save()
def test_stale_days(self):
cur_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
cur_settings.allow_stale = 0
cur_settings.stale_days = 0
self.assertRaises(frappe.ValidationError, cur_settings.save)
cur_settings.stale_days = -1
self.assertRaises(frappe.ValidationError, cur_settings.save)

View File

@@ -55,13 +55,13 @@ frappe.ui.form.on('Asset', {
});
}
frm.trigger("show_graph");
frm.trigger("setup_chart");
}
},
show_graph: function(frm) {
var x_intervals = ["x", frm.doc.purchase_date];
var asset_values = ["Asset Value", frm.doc.gross_purchase_amount];
setup_chart: function(frm) {
var x_intervals = [frm.doc.purchase_date];
var asset_values = [frm.doc.gross_purchase_amount];
var last_depreciation_date = frm.doc.purchase_date;
if(frm.doc.opening_accumulated_depreciation) {
@@ -94,32 +94,21 @@ frappe.ui.form.on('Asset', {
last_depreciation_date = frm.doc.disposal_date;
}
frm.dashboard.setup_chart({
frm.dashboard.render_graph({
title: "Asset Value",
data: {
x: 'x',
columns: [x_intervals, asset_values],
regions: {
'Asset Value': [{'start': last_depreciation_date, 'style':'dashed'}]
}
labels: x_intervals,
datasets: [{
color: 'green',
values: asset_values,
formatted: asset_values.map(d => d.toFixed(2))
}]
},
legend: {
show: false
},
axis: {
x: {
type: 'timeseries',
tick: {
format: "%d-%m-%Y"
}
},
y: {
min: 0,
padding: {bottom: 10}
}
}
type: 'line'
});
},
item_code: function(frm) {
if(frm.doc.item_code) {
frappe.call({

View File

@@ -13,6 +13,7 @@ class TestAsset(unittest.TestCase):
def setUp(self):
set_depreciation_settings_in_company()
create_asset()
frappe.db.sql("delete from `tabTax Rule`")
def test_purchase_asset(self):
asset = frappe.get_doc("Asset", "Macbook Pro 1")

View File

@@ -0,0 +1,22 @@
QUnit.module('Account');
QUnit.test("test Bank Reconciliation", function(assert) {
assert.expect(0);
let done = assert.async();
frappe.run_serially([
() => frappe.set_route('Form', 'Bank Reconciliation'),
() => cur_frm.set_value('bank_account','Cash - FT'),
() => frappe.click_button('Get Payment Entries'),
() => {
for(var i=0;i<=cur_frm.doc.payment_entries.length-1;i++){
cur_frm.doc.payment_entries[i].clearance_date = frappe.datetime.add_days(frappe.datetime.now_date(), 2);
}
},
() => {cur_frm.refresh_fields('payment_entries');},
() => frappe.click_button('Update Clearance Date'),
() => frappe.timeout(0.5),
() => frappe.click_button('Close'),
() => done()
]);
});

View File

@@ -36,7 +36,7 @@ class GLEntry(Document):
validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice'] \
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees'] \
and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
self.against_voucher)
@@ -196,7 +196,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
frappe.throw(_("Outstanding for {0} cannot be less than zero ({1})").format(against_voucher, fmt_money(bal)))
# Update outstanding amt on against voucher
if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
ref_doc.db_set('outstanding_amount', bal)
ref_doc.set_status(update=True)

View File

@@ -1337,6 +1337,67 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription_section",
"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": "Subscription Section",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription",
"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": "Subscription",
"length": 0,
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1382,7 +1443,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-13 14:29:09.794076",
"modified": "2017-08-31 11:21:09.442695",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",

View File

@@ -12,8 +12,8 @@ from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo
from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status
class JournalEntry(AccountsController):
def __init__(self, arg1, arg2=None):
super(JournalEntry, self).__init__(arg1, arg2)
def __init__(self, *args, **kwargs):
super(JournalEntry, self).__init__(*args, **kwargs)
def get_feed(self):
return self.voucher_type
@@ -54,7 +54,7 @@ class JournalEntry(AccountsController):
def update_advance_paid(self):
advance_paid = frappe._dict()
for d in self.get("accounts"):
if d.is_advance:
if d.is_advance == "Yes":
if d.reference_type in ("Sales Order", "Purchase Order"):
advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
@@ -76,7 +76,7 @@ class JournalEntry(AccountsController):
def unlink_advance_entry_reference(self):
for d in self.get("accounts"):
if d.is_advance and d.reference_type in ("Sales Invoice", "Purchase Invoice"):
if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"):
doc = frappe.get_doc(d.reference_type, d.reference_name)
doc.delink_advance_entries(self.name)
d.reference_type = ''

View File

@@ -0,0 +1,39 @@
QUnit.module('Journal Entry');
QUnit.test("test journal entry", function(assert) {
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Journal Entry', [
{posting_date:frappe.datetime.add_days(frappe.datetime.nowdate(), 0)},
{accounts: [
[
{'account':'Debtors - '+frappe.get_abbr(frappe.defaults.get_default('Company'))},
{'party_type':'Customer'},
{'party':'Test Customer 1'},
{'credit_in_account_currency':1000},
{'is_advance':'Yes'},
],
[
{'account':'HDFC - '+frappe.get_abbr(frappe.defaults.get_default('Company'))},
{'debit_in_account_currency':1000},
]
]},
{cheque_no:1234},
{cheque_date: frappe.datetime.add_days(frappe.datetime.nowdate(), -1)},
{user_remark: 'Test'},
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.total_debit==1000, "total debit correct");
assert.ok(cur_frm.doc.total_credit==1000, "total credit correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => done()
]);
});

View File

@@ -12,7 +12,8 @@ frappe.ui.form.on('Payment Entry', {
setup: function(frm) {
frm.set_query("paid_from", function() {
var party_account_type = frm.doc.party_type=="Customer" ? "Receivable" : "Payable";
var party_account_type = in_list(["Customer", "Student"], frm.doc.party_type) ?
"Receivable" : "Payable";
var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ?
["Bank", "Cash"] : party_account_type;
@@ -28,13 +29,14 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("party_type", function() {
return{
"filters": {
"name": ["in",["Customer","Supplier", "Employee"]],
"name": ["in",["Customer","Supplier", "Employee", "Student"]],
}
}
});
frm.set_query("paid_to", function() {
var party_account_type = frm.doc.party_type=="Customer" ? "Receivable" : "Payable";
var party_account_type = in_list(["Customer", "Student"], frm.doc.party_type) ?
"Receivable" : "Payable";
var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ?
["Bank", "Cash"] : party_account_type;
@@ -72,6 +74,8 @@ frappe.ui.form.on('Payment Entry', {
var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
} else if (frm.doc.party_type=="Employee") {
var doctypes = ["Expense Claim", "Journal Entry"];
} else if (frm.doc.party_type=="Student") {
var doctypes = ["Fees"];
} else {
var doctypes = ["Journal Entry"];
}
@@ -85,7 +89,7 @@ frappe.ui.form.on('Payment Entry', {
child = locals[cdt][cdn];
filters = {"docstatus": 1, "company": doc.company};
party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice',
'Purchase Order', 'Expense Claim'];
'Purchase Order', 'Expense Claim', 'Fees'];
if (in_list(party_type_doctypes, child.reference_doctype)) {
filters[doc.party_type.toLowerCase()] = doc.party;
@@ -207,19 +211,13 @@ frappe.ui.form.on('Payment Entry', {
frm.set_value(field, null);
});
} else {
if(!frm.doc.party)
{
if (frm.doc.payment_type=="Receive"){
frm.set_value("party_type", "Customer");
}
}
else
{
frm.events.party(frm);
if(frm.doc.party) {
frm.events.party(frm);
}
if(frm.doc.mode_of_payment)
if(frm.doc.mode_of_payment) {
frm.events.mode_of_payment(frm);
}
}
},
@@ -254,6 +252,7 @@ frappe.ui.form.on('Payment Entry', {
date: frm.doc.posting_date
},
callback: function(r, rt) {
console.log(r, rt);
if(r.message) {
if(frm.doc.payment_type == "Receive") {
frm.set_value("paid_from", r.message.party_account);
@@ -404,6 +403,9 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_difference_amount(frm);
}
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed());
},
target_exchange_rate: function(frm) {
@@ -422,6 +424,9 @@ frappe.ui.form.on('Payment Entry', {
frm.events.set_difference_amount(frm);
}
frm.set_paid_amount_based_on_received_amount = false;
// Make read only if Accounts Settings doesn't allow stale rates
frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed());
},
paid_amount: function(frm) {
@@ -502,6 +507,8 @@ frappe.ui.form.on('Payment Entry', {
c.due_date = d.due_date
c.total_amount = d.invoice_amount;
c.outstanding_amount = d.outstanding_amount;
c.bill_no = d.bill_no;
if(!in_list(["Sales Order", "Purchase Order", "Expense Claim"], d.voucher_type)) {
if(flt(d.outstanding_amount) > 0)
total_positive_outstanding += flt(d.outstanding_amount);
@@ -641,12 +648,12 @@ frappe.ui.form.on('Payment Entry', {
set_difference_amount: function(frm) {
var unallocated_amount = 0;
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
function(d) { return flt(d.amount) }));
if(frm.doc.party) {
var party_amount = frm.doc.payment_type=="Receive" ?
frm.doc.paid_amount : frm.doc.received_amount;
var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
function(d) { return flt(d.amount) }));
if(frm.doc.total_allocated_amount < party_amount) {
if(frm.doc.payment_type == "Receive") {
@@ -672,11 +679,7 @@ frappe.ui.form.on('Payment Entry', {
difference_amount = flt(frm.doc.base_paid_amount) - flt(frm.doc.base_received_amount);
}
$.each(frm.doc.deductions || [], function(i, d) {
if(d.amount) difference_amount -= flt(d.amount);
})
frm.set_value("difference_amount", difference_amount);
frm.set_value("difference_amount", difference_amount - total_deductions);
frm.events.hide_unhide_fields(frm);
},

View File

@@ -1659,6 +1659,67 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription_section",
"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": "Subscription Section",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription",
"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": "Subscription",
"length": 0,
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1730,7 +1791,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-13 14:29:04.244537",
"modified": "2017-08-31 11:20:37.578469",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",

View File

@@ -100,8 +100,8 @@ class PaymentEntry(AccountsController):
if not self.party:
frappe.throw(_("Party is mandatory"))
self.party_name = frappe.db.get_value(self.party_type, self.party,
self.party_type.lower() + "_name")
_party_name = "title" if self.party_type == "Student" else self.party_type.lower() + "_name"
self.party_name = frappe.db.get_value(self.party_type, self.party, _party_name)
if self.party:
if not self.party_balance:
@@ -149,7 +149,7 @@ class PaymentEntry(AccountsController):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
if self.party_account:
party_account_type = "Receivable" if self.party_type=="Customer" else "Payable"
party_account_type = "Receivable" if self.party_type in ("Customer", "Student") else "Payable"
self.validate_account_type(self.party_account, [party_account_type])
def validate_bank_accounts(self):
@@ -182,7 +182,9 @@ class PaymentEntry(AccountsController):
frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
def validate_reference_documents(self):
if self.party_type == "Customer":
if self.party_type == "Student":
valid_reference_doctypes = ("Fees")
elif self.party_type == "Customer":
valid_reference_doctypes = ("Sales Order", "Sales Invoice", "Journal Entry")
elif self.party_type == "Supplier":
valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
@@ -209,17 +211,19 @@ class PaymentEntry(AccountsController):
else:
self.validate_journal_entry()
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
if self.party_type=="Customer":
if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim", "Fees"):
if self.party_type == "Customer":
ref_party_account = ref_doc.debit_to
elif self.party_type == "Student":
ref_party_account = ref_doc.receivable_account
elif self.party_type=="Supplier":
ref_party_account = ref_doc.credit_to
elif self.party_type=="Employee":
ref_party_account = ref_doc.payable_account
if ref_party_account != self.party_account:
frappe.throw(_("{0} {1} is associated with {2}, but Party Account is {3}")
.format(d.reference_doctype, d.reference_name, ref_party_account, self.party_account))
frappe.throw(_("{0} {1} is associated with {2}, but Party Account is {3}")
.format(d.reference_doctype, d.reference_name, ref_party_account, self.party_account))
if ref_doc.docstatus != 1:
frappe.throw(_("{0} {1} must be submitted")
@@ -302,11 +306,10 @@ class PaymentEntry(AccountsController):
else:
self.difference_amount = self.base_paid_amount - flt(self.base_received_amount)
for d in self.get("deductions"):
if d.amount:
self.difference_amount -= flt(d.amount)
total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
self.difference_amount = flt(self.difference_amount, self.precision("difference_amount"))
self.difference_amount = flt(self.difference_amount - total_deductions,
self.precision("difference_amount"))
def clear_unallocated_reference_document_rows(self):
self.set("references", self.get("references", {"allocated_amount": ["not in", [0, None, ""]]}))
@@ -393,7 +396,7 @@ class PaymentEntry(AccountsController):
if self.payment_type=="Receive":
against_account = self.paid_to
else:
against_account = self.paid_from
against_account = self.paid_from
party_gl_dict = self.get_gl_dict({
@@ -404,7 +407,7 @@ class PaymentEntry(AccountsController):
"account_currency": self.party_account_currency
})
dr_or_cr = "credit" if self.party_type == "Customer" else "debit"
dr_or_cr = "credit" if self.party_type in ["Customer", "Student"] else "debit"
for d in self.get("references"):
gle = party_gl_dict.copy()
@@ -489,9 +492,14 @@ class PaymentEntry(AccountsController):
doc = frappe.get_doc("Expense Claim", d.reference_name)
update_reimbursed_amount(doc)
def on_recurring(self, reference_doc, subscription_doc):
self.reference_no = reference_doc.name
self.reference_date = nowdate()
@frappe.whitelist()
def get_outstanding_reference_documents(args):
args = json.loads(args)
if isinstance(args, basestring):
args = json.loads(args)
party_account_currency = get_account_currency(args.get("party_account"))
company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency")
@@ -499,10 +507,12 @@ def get_outstanding_reference_documents(args):
# Get negative outstanding sales /purchase invoices
total_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), total_field)
negative_outstanding_invoices = []
if (args.get("party_type") != "Student"):
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"),
args.get("party"), args.get("party_account"), total_field)
# Get positive outstanding sales /purchase invoices
# Get positive outstanding sales /purchase invoices/ Fees
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"))
@@ -515,10 +525,14 @@ def get_outstanding_reference_documents(args):
d["exchange_rate"] = get_exchange_rate(
party_account_currency, company_currency, d.posting_date
)
if d.voucher_type in ("Purchase Invoice"):
d["bill_no"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "bill_no")
# Get all SO / PO which are not fully billed or aginst which full advance not paid
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
party_account_currency, company_currency)
orders_to_be_billed = []
if (args.get("party_type") != "Student"):
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
args.get("party"), party_account_currency, company_currency)
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
@@ -633,7 +647,11 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
total_amount = outstanding_amount = exchange_rate = None
ref_doc = frappe.get_doc(reference_doctype, reference_name)
if reference_doctype != "Journal Entry":
if reference_doctype == "Fees":
total_amount = ref_doc.get("grand_total")
exchange_rate = 1
outstanding_amount = ref_doc.get("outstanding_amount")
elif reference_doctype != "Journal Entry":
if party_account_currency == ref_doc.company_currency:
if ref_doc.doctype == "Expense Claim":
total_amount = ref_doc.total_sanctioned_amount
@@ -676,19 +694,23 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
party_type = "Supplier"
elif dt in ("Expense Claim"):
party_type = "Employee"
elif dt in ("Fees"):
party_type = "Student"
# party account
if dt == "Sales Invoice":
party_account = doc.debit_to
elif dt == "Purchase Invoice":
party_account = doc.credit_to
elif dt == "Fees":
party_account = doc.receivable_account
else:
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
# payment type
if (dt == "Sales Order" or (dt=="Sales Invoice" and doc.outstanding_amount > 0)) \
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees") and doc.outstanding_amount > 0)) \
or (dt=="Purchase Invoice" and doc.outstanding_amount < 0):
payment_type = "Receive"
else:
@@ -704,6 +726,9 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
elif dt in ("Expense Claim"):
grand_total = doc.total_sanctioned_amount
outstanding_amount = doc.total_sanctioned_amount - doc.total_amount_reimbursed
elif dt == "Fees":
grand_total = doc.grand_total
outstanding_amount = doc.outstanding_amount
else:
total_field = "base_grand_total" if party_account_currency == doc.company_currency else "grand_total"
grand_total = flt(doc.get(total_field))
@@ -745,6 +770,7 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
pe.append("references", {
"reference_doctype": dt,
"reference_name": dn,
"bill_no": doc.get("bill_no"),
"due_date": doc.get("due_date"),
"total_amount": grand_total,
"outstanding_amount": outstanding_amount,

View File

@@ -267,3 +267,65 @@ class TestPaymentEntry(unittest.TestCase):
return frappe.db.sql("""select account, debit, credit, against_voucher
from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
order by account asc""", voucher_no, as_dict=1)
def test_payment_entry_write_off_difference(self):
si = create_sales_invoice()
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.received_amount = pe.paid_amount = 110
pe.insert()
self.assertEqual(pe.unallocated_amount, 10)
pe.received_amount = pe.paid_amount = 95
pe.append("deductions", {
"account": "_Test Write Off - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": 5
})
pe.save()
self.assertEqual(pe.unallocated_amount, 0)
self.assertEqual(pe.difference_amount, 0)
pe.submit()
expected_gle = dict((d[0], d) for d in [
["Debtors - _TC", 0, 100, si.name],
["_Test Cash - _TC", 95, 0, None],
["_Test Write Off - _TC", 5, 0, None]
])
self.validate_gl_entries(pe.name, expected_gle)
def test_payment_entry_exchange_gain_loss(self):
si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
currency="USD", conversion_rate=50)
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
pe.reference_no = "1"
pe.reference_date = "2016-01-01"
pe.target_exchange_rate = 55
pe.append("deductions", {
"account": "_Test Exchange Gain/Loss - _TC",
"cost_center": "_Test Cost Center - _TC",
"amount": -500
})
pe.save()
self.assertEqual(pe.unallocated_amount, 0)
self.assertEqual(pe.difference_amount, 0)
pe.submit()
expected_gle = dict((d[0], d) for d in [
["_Test Receivable USD - _TC", 0, 5000, si.name],
["_Test Bank USD - _TC", 5500, 0, None],
["_Test Exchange Gain/Loss - _TC", 0, 500, None],
])
self.validate_gl_entries(pe.name, expected_gle)
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)

View File

@@ -0,0 +1,55 @@
QUnit.module('Payment Entry');
QUnit.test("test payment entry", function(assert) {
assert.expect(6);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Sales Invoice', [
{customer: 'Test Customer 1'},
{items: [
[
{'item_code': 'Test Product 1'},
{'qty': 1},
{'rate': 101},
]
]}
]);
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
() => frappe.click_button('Make'),
() => frappe.timeout(1),
() => frappe.click_link('Payment'),
() => frappe.timeout(2),
() => {
assert.equal(frappe.get_route()[1], 'Payment Entry',
'made payment entry');
assert.equal(cur_frm.doc.party, 'Test Customer 1',
'customer set in payment entry');
assert.equal(cur_frm.doc.paid_amount, 101,
'paid amount set in payment entry');
assert.equal(cur_frm.doc.references[0].allocated_amount, 101,
'amount allocated against sales invoice');
},
() => frappe.timeout(1),
() => cur_frm.set_value('paid_amount', 100),
() => frappe.timeout(1),
() => {
frappe.model.set_value("Payment Entry Reference", cur_frm.doc.references[0].name,
"allocated_amount", 101);
},
() => frappe.timeout(1),
() => frappe.click_button('Write Off Difference Amount'),
() => frappe.timeout(1),
() => {
assert.equal(cur_frm.doc.difference_amount, 0, 'difference amount is zero');
assert.equal(cur_frm.doc.deductions[0].amount, 1, 'Write off amount = 1');
},
() => done()
]);
});

View File

@@ -0,0 +1,60 @@
QUnit.module('Payment Entry');
QUnit.test("test payment entry", function(assert) {
assert.expect(7 );
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Purchase Invoice', [
{supplier: 'Test Supplier'},
{bill_no: 'in1234'},
{items: [
[
{'qty': 2},
{'item_code': 'Test Product 1'},
{'rate':1000},
]
]},
{update_stock:1},
{supplier_address: 'Test1-Billing'},
{contact_person: 'Contact 3-Test Supplier'},
{tc_name: 'Test Term 1'},
{terms: 'This is just a Test'}
]);
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),
() => frappe.click_button('Make'),
() => frappe.timeout(2),
() => frappe.click_link('Payment'),
() => frappe.timeout(3),
() => cur_frm.set_value('mode_of_payment','Cash'),
() => frappe.timeout(3),
() => {
assert.equal(frappe.get_route()[1], 'Payment Entry',
'made payment entry');
assert.equal(cur_frm.doc.party, 'Test Supplier',
'supplier set in payment entry');
assert.equal(cur_frm.doc.paid_amount, 2000,
'paid amount set in payment entry');
assert.equal(cur_frm.doc.references[0].allocated_amount, 2000,
'amount allocated against purchase invoice');
assert.equal(cur_frm.doc.references[0].bill_no, 'in1234',
'invoice number allocated against purchase invoice');
assert.equal(cur_frm.get_field('total_allocated_amount').value, 2000,
'correct amount allocated in Write Off');
assert.equal(cur_frm.get_field('unallocated_amount').value, 0,
'correct amount unallocated in Write Off');
},
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => done()
]);
});

View File

@@ -0,0 +1,28 @@
QUnit.module('Accounts');
QUnit.test("test payment entry", function(assert) {
assert.expect(1);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Payment Entry', [
{payment_type:'Receive'},
{mode_of_payment:'Cash'},
{party_type:'Customer'},
{party:'Test Customer 3'},
{paid_amount:675},
{reference_no:123},
{reference_date: frappe.datetime.add_days(frappe.datetime.nowdate(), 0)},
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.total_allocated_amount==675, "Allocated AmountCorrect");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => done()
]);
});

View File

@@ -0,0 +1,67 @@
QUnit.module('Payment Entry');
QUnit.test("test payment entry", function(assert) {
assert.expect(8);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Sales Invoice', [
{customer: 'Test Customer 1'},
{company: 'For Testing'},
{currency: 'INR'},
{selling_price_list: '_Test Price List'},
{items: [
[
{'qty': 1},
{'item_code': 'Test Product 1'},
]
]}
]);
},
() => frappe.timeout(1),
() => cur_frm.save(),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1.5),
() => frappe.click_button('Close'),
() => frappe.timeout(0.5),
() => frappe.click_button('Make'),
() => frappe.timeout(1),
() => frappe.click_link('Payment'),
() => frappe.timeout(2),
() => cur_frm.set_value("paid_to", "_Test Cash - FT"),
() => frappe.timeout(0.5),
() => {
assert.equal(frappe.get_route()[1], 'Payment Entry', 'made payment entry');
assert.equal(cur_frm.doc.party, 'Test Customer 1', 'customer set in payment entry');
assert.equal(cur_frm.doc.paid_from, 'Debtors - FT', 'customer account set in payment entry');
assert.equal(cur_frm.doc.paid_amount, 100, 'paid amount set in payment entry');
assert.equal(cur_frm.doc.references[0].allocated_amount, 100,
'amount allocated against sales invoice');
},
() => cur_frm.set_value('paid_amount', 95),
() => frappe.timeout(1),
() => {
frappe.model.set_value("Payment Entry Reference",
cur_frm.doc.references[0].name, "allocated_amount", 100);
},
() => frappe.timeout(.5),
() => {
assert.equal(cur_frm.doc.difference_amount, 5, 'difference amount is 5');
},
() => {
frappe.db.set_value("Company", "For Testing", "write_off_account", "_Test Write Off - FT");
frappe.timeout(1);
frappe.db.set_value("Company", "For Testing",
"exchange_gain_loss_account", "_Test Exchange Gain/Loss - FT");
},
() => frappe.timeout(1),
() => frappe.click_button('Write Off Difference Amount'),
() => frappe.timeout(2),
() => {
assert.equal(cur_frm.doc.difference_amount, 0, 'difference amount is zero');
assert.equal(cur_frm.doc.deductions[0].amount, 5, 'Write off amount = 5');
},
() => done()
]);
});

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -12,6 +13,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +75,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -101,6 +105,38 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "bill_no",
"fieldtype": "Data",
"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": "Supplier Invoice No",
"length": 0,
"no_copy": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -129,6 +165,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -158,6 +195,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -187,6 +225,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -216,10 +255,12 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:(doc.reference_doctype=='Purchase Invoice')",
"fieldname": "exchange_rate",
"fieldtype": "Float",
"hidden": 0,
@@ -245,17 +286,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-02-17 16:47:17.156256",
"modified": "2017-10-16 17:37:01.192312",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry Reference",
@@ -270,4 +311,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
}

View File

@@ -35,7 +35,6 @@ class PaymentRequest(Document):
def on_submit(self):
send_mail = True
self.make_communication_entry()
ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
if (hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart") \
@@ -45,6 +44,7 @@ class PaymentRequest(Document):
if send_mail:
self.set_payment_request_url()
self.send_email()
self.make_communication_entry()
def on_cancel(self):
self.check_if_payment_entry_exists()
@@ -69,8 +69,11 @@ class PaymentRequest(Document):
self.db_set('status', 'Initiated')
def get_payment_url(self):
data = frappe.db.get_value(self.reference_doctype, self.reference_name,
["company", "customer_name"], as_dict=1)
if self.reference_doctype != "Fees":
data = frappe.db.get_value(self.reference_doctype, self.reference_name, ["company", "customer_name"], as_dict=1)
else:
data = frappe.db.get_value(self.reference_doctype, self.reference_name, ["student_name"], as_dict=1)
data.update({"company": frappe.defaults.get_defaults().company})
controller = get_payment_gateway_controller(self.payment_gateway)
controller.validate_transaction_currency(self.currency)
@@ -277,6 +280,9 @@ def get_amount(ref_doc, dt):
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
if dt == "Fees":
grand_total = ref_doc.outstanding_amount
if grand_total > 0 :
return grand_total

View File

@@ -8,10 +8,6 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
return { filters: { selling: 1 } };
});
frm.set_query("print_format", function() {
return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} };
});
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
@@ -27,6 +23,27 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
});
frappe.ui.form.on('POS Profile', {
setup: function(frm) {
frm.set_query("online_print_format", function() {
return {
filters: [
['Print Format', 'doc_type', '=', 'Sales Invoice'],
['Print Format', 'print_format_type', '!=', 'Js'],
]
};
});
frm.set_query("print_format", function() {
return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} };
});
frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'use_pos_in_offline_mode', (r) => {
is_offline = r && cint(r.use_pos_in_offline_mode)
frm.toggle_display('offline_pos_section', is_offline);
frm.toggle_display('print_format_for_online', !is_offline);
});
},
refresh: function(frm) {
if(frm.doc.company) {
frm.trigger("toggle_display_account_head");

View File

@@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
"autoname": "field:pos_profile_name",
"beta": 0,
"creation": "2013-05-24 12:15:51",
"custom": 0,
@@ -11,6 +11,96 @@
"doctype": "DocType",
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "disabled",
"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": "Disabled",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_2",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "pos_profile_name",
"fieldtype": "Data",
"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": "POS Profile Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -112,9 +202,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "update_stock",
"fieldname": "warehouse",
"fieldtype": "Link",
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -122,13 +211,11 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Warehouse",
"label": "Ignore Pricing Rule",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -145,8 +232,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "campaign",
"fieldtype": "Link",
"fieldname": "allow_delete",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -154,10 +241,39 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Campaign",
"label": "Allow Delete",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_user_to_edit_rate",
"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": "Allow user to edit Rate",
"length": 0,
"no_copy": 0,
"options": "Campaign",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -300,7 +416,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "currency",
"depends_on": "update_stock",
"fieldname": "warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -309,19 +426,19 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Currency",
"label": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "currency",
"oldfieldtype": "Select",
"options": "Currency",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -332,8 +449,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"fieldname": "campaign",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -341,69 +458,10 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Ignore Pricing Rule",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_delete",
"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": "Allow Delete",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_user_to_edit_rate",
"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": "Allow user to edit Rate",
"label": "Campaign",
"length": 0,
"no_copy": 0,
"options": "Campaign",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -422,6 +480,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"hidden": 0,
@@ -482,6 +541,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_14",
"fieldtype": "Section Break",
"hidden": 0,
@@ -602,6 +662,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_16",
"fieldtype": "Section Break",
"hidden": 0,
@@ -631,8 +692,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Point of Sale",
"fieldname": "print_format",
"fieldname": "print_format_for_online",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -641,7 +701,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Print Format",
"label": "Print Format for Online",
"length": 0,
"no_copy": 0,
"options": "Print Format",
@@ -822,7 +882,7 @@
"columns": 0,
"fieldname": "apply_discount",
"fieldtype": "Check",
"hidden": 0,
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
@@ -836,7 +896,7 @@
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -851,7 +911,7 @@
"collapsible": 0,
"columns": 0,
"default": "Grand Total",
"depends_on": "apply_discount",
"depends_on": "",
"fieldname": "apply_discount_on",
"fieldtype": "Select",
"hidden": 0,
@@ -883,7 +943,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer_details",
"depends_on": "",
"fieldname": "offline_pos_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -892,7 +953,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "New Customer Details",
"label": "Offline POS Section",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -969,6 +1030,38 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Point of Sale",
"fieldname": "print_format",
"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": "Print Format",
"length": 0,
"no_copy": 0,
"options": "Print Format",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1006,6 +1099,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_19",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1015,6 +1109,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Accounting",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -1029,6 +1124,38 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "currency",
"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": "Currency",
"length": 0,
"no_copy": 0,
"oldfieldname": "currency",
"oldfieldtype": "Select",
"options": "Currency",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1123,38 +1250,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "taxes_and_charges",
"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": "Taxes and Charges",
"length": 0,
"no_copy": 0,
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Sales Taxes and Charges Template",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1278,6 +1373,38 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "taxes_and_charges",
"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": "Taxes and Charges",
"length": 0,
"no_copy": 0,
"oldfieldname": "charge",
"oldfieldtype": "Link",
"options": "Sales Taxes and Charges Template",
"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,
"unique": 0
}
],
"has_web_view": 0,
@@ -1291,7 +1418,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-28 03:40:03.253088",
"modified": "2017-10-27 06:45:32.957674",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",

View File

@@ -41,6 +41,7 @@ def make_pos_profile():
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"income_account": "Sales - _TC",
"name": "_Test POS Profile",
"pos_profile_name": "_Test POS Profile",
"naming_series": "_T-POS Profile-",
"selling_price_list": "_Test Price List",
"territory": "_Test Territory",

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('POS Settings', {
refresh: function() {
}
});

View File

@@ -0,0 +1,133 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-08-28 16:46:41.732676",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "use_pos_in_offline_mode",
"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": "Use POS in Offline Mode",
"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,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-09-11 13:57:28.787023",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "Sales User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class POSSettings(Document):
def validate(self):
self.set_link_for_pos()
def set_link_for_pos(self):
link = 'pos' if self.use_pos_in_offline_mode else 'point-of-sale'
desktop_icon = frappe.db.get_value('Desktop Icon',
{'standard': 1, 'module_name': 'POS'}, 'name')
if desktop_icon:
frappe.db.set_value('Desktop Icon', desktop_icon, 'link', link)

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: POS Settings", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new POS Settings
() => frappe.tests.make('POS Settings', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import unittest
class TestPOSSettings(unittest.TestCase):
pass

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
@@ -12,6 +13,7 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -40,6 +42,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -69,6 +72,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -99,6 +103,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -129,6 +134,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -159,6 +165,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -189,6 +196,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -217,6 +225,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -247,6 +256,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -275,6 +285,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -303,6 +314,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -331,6 +343,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -359,6 +372,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -387,6 +401,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -417,6 +432,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -447,6 +463,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -477,6 +494,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -507,6 +525,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -537,6 +556,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -567,6 +587,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -597,6 +618,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -627,6 +649,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -655,6 +678,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -683,6 +707,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -711,6 +736,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -739,6 +765,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -767,6 +794,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -796,6 +824,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -824,6 +853,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -851,6 +881,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -880,6 +911,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -910,6 +942,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -941,6 +974,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -969,6 +1003,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -988,7 +1023,7 @@
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "2",
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -1000,6 +1035,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1028,6 +1064,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1058,6 +1095,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1085,13 +1123,14 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.price_or_discount==\"Price\"",
"fieldname": "price",
"fieldtype": "Float",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1114,6 +1153,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1143,6 +1183,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1173,6 +1214,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1202,6 +1244,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1230,18 +1273,18 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-gift",
"idx": 1,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 16:21:28.446208",
"modified": "2017-09-27 08:31:38.432574",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",

View File

@@ -348,6 +348,8 @@ def apply_internal_priority(pricing_rules, field_set, args):
return filtered_rules or pricing_rules
def set_transaction_type(args):
if args.transaction_type:
return
if args.doctype in ("Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"):
args.transaction_type = "selling"
elif args.doctype in ("Material Request", "Supplier Quotation", "Purchase Order",
@@ -356,4 +358,4 @@ def set_transaction_type(args):
elif args.customer:
args.transaction_type = "selling"
else:
args.transaction_type = "buying"
args.transaction_type = "buying"

View File

@@ -46,6 +46,12 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
cur_frm.add_custom_button(__('Return / Debit Note'),
this.make_debit_note, __("Make"));
}
if(!doc.subscription) {
cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __("Make"))
}
}
if(doc.docstatus===0) {
@@ -343,6 +349,7 @@ frappe.ui.form.on("Purchase Invoice", {
'Payment Entry': 'Payment'
}
},
onload: function(frm) {
$.each(["warehouse", "rejected_warehouse"], function(i, field) {
frm.set_query(field, "items", function() {
@@ -370,5 +377,5 @@ frappe.ui.form.on("Purchase Invoice", {
erpnext.buying.get_default_bom(frm);
}
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
}
})
},
})

View File

@@ -2072,6 +2072,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2166,6 +2197,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -3352,11 +3414,9 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "is_recurring",
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2 && !doc.__islocal",
"fieldname": "recurring_invoice",
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -3365,12 +3425,12 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Recurring Invoice",
"label": "Subscription Section",
"length": 0,
"no_copy": 0,
"options": "fa fa-time",
"permlevel": 0,
"print_hide": 1,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -3386,70 +3446,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2",
"description": "",
"fieldname": "is_recurring",
"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": "Is Recurring",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "Select the period when the invoice will be generated automatically",
"fieldname": "recurring_type",
"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": "Recurring Type",
"length": 0,
"no_copy": 1,
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"depends_on": "",
"description": "Start date of current invoice's period",
"fieldname": "from_date",
"fieldtype": "Date",
@@ -3480,7 +3477,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"depends_on": "",
"description": "End date of current invoice's period",
"fieldname": "to_date",
"fieldtype": "Date",
@@ -3505,138 +3502,13 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"fieldname": "submit_on_creation",
"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": "Submit on creation",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "notify_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 by email",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc",
"fieldname": "repeat_on_day_of_month",
"fieldtype": "Int",
"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": "Repeat on Day of Month",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which recurring invoice will be stop",
"fieldname": "end_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": "End Date",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_82",
"fieldname": "column_break_114",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -3648,101 +3520,8 @@
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which next invoice will be generated. It is generated on submit.",
"fieldname": "next_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": "Next Date",
"length": 0,
"no_copy": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "The unique id for tracking all recurring invoices. It is generated on submit.",
"fieldname": "recurring_id",
"fieldtype": "Data",
"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": "Recurring Id",
"length": 0,
"no_copy": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"description": "Enter Email Address separated by commas, invoice will be mailed automatically on particular date",
"fieldname": "notification_email_address",
"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": "Notification Email Address",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -3758,8 +3537,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring==1",
"fieldname": "recurring_print_format",
"fieldname": "subscription",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -3768,15 +3546,15 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Recurring Print Format",
"label": "Subscription",
"length": 0,
"no_copy": 0,
"options": "Print Format",
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -3797,7 +3575,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-07-19 13:53:48.673757",
"modified": "2017-10-24 12:51:51.199594",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -15,14 +15,15 @@ from erpnext.stock import get_warehouse_account_map
from erpnext.accounts.general_ledger import make_gl_entries, merge_similar_entries, delete_gl_entries
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.buying.utils import check_for_closed_status
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
}
class PurchaseInvoice(BuyingController):
def __init__(self, arg1, arg2=None):
super(PurchaseInvoice, self).__init__(arg1, arg2)
def __init__(self, *args, **kwargs):
super(PurchaseInvoice, self).__init__(*args, **kwargs)
self.status_updater = [{
'source_dt': 'Purchase Invoice Item',
'target_dt': 'Purchase Order Item',
@@ -353,6 +354,7 @@ class PurchaseInvoice(BuyingController):
self.make_payment_gl_entries(gl_entries)
self.make_write_off_gl_entry(gl_entries)
self.make_gle_for_rounding_adjustment(gl_entries)
return gl_entries
@@ -584,6 +586,21 @@ class PurchaseInvoice(BuyingController):
})
)
def make_gle_for_rounding_adjustment(self, gl_entries):
if self.rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
gl_entries.append(
self.get_gl_dict({
"account": round_off_account,
"against": self.supplier,
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
"cost_center": round_off_cost_center,
}
))
def on_cancel(self):
self.check_for_closed_status()
@@ -667,7 +684,7 @@ class PurchaseInvoice(BuyingController):
if account_type != 'Fixed Asset':
frappe.throw(_("Row {0}# Account must be of type 'Fixed Asset'").format(d.idx))
def on_recurring(self, reference_doc):
def on_recurring(self, reference_doc, subscription_doc):
self.due_date = None
@frappe.whitelist()

View File

@@ -8,7 +8,8 @@ def get_data():
'Payment Entry': 'reference_name',
'Payment Request': 'reference_name',
'Landed Cost Voucher': 'receipt_document',
'Purchase Invoice': 'return_against'
'Purchase Invoice': 'return_against',
'Subscription': 'reference_document'
},
'internal_links': {
'Purchase Order': ['items', 'purchase_order'],
@@ -27,5 +28,9 @@ def get_data():
'label': _('Returns'),
'items': ['Purchase Invoice']
},
{
'label': _('Subscription'),
'items': ['Subscription']
},
]
}

View File

@@ -7,6 +7,7 @@ QUnit.test("test purchase invoice", function(assert) {
() => {
return frappe.tests.make('Purchase Invoice', [
{supplier: 'Test Supplier'},
{bill_no: 'in123'},
{items: [
[
{'qty': 5},
@@ -36,7 +37,7 @@ QUnit.test("test purchase invoice", function(assert) {
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => frappe.timeout(1),
() => done()
]);
});

View File

@@ -256,10 +256,6 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertFalse(frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_type='Purchase Invoice' and reference_name=%s""", pi.name))
def test_recurring_invoice(self):
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
test_recurring_document(self, test_records)
def test_total_purchase_cost_for_project(self):
existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount)
from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""")
@@ -477,6 +473,7 @@ class TestPurchaseInvoice(unittest.TestCase):
import test_records as jv_test_records
jv = frappe.copy_doc(jv_test_records[1])
jv.accounts[0].is_advance = 'Yes'
jv.insert()
jv.submit()

View File

@@ -88,10 +88,11 @@ def update_pos_profile_data(doc, pos_profile, company_data):
doc.naming_series = pos_profile.get('naming_series') or 'SINV-'
doc.letter_head = pos_profile.get('letter_head') or company_data.default_letter_head
doc.ignore_pricing_rule = pos_profile.get('ignore_pricing_rule') or 0
doc.apply_discount_on = pos_profile.get('apply_discount_on') if pos_profile.get('apply_discount') else ''
doc.apply_discount_on = pos_profile.get('apply_discount_on') or 'Grand Total'
doc.customer_group = pos_profile.get('customer_group') or get_root('Customer Group')
doc.territory = pos_profile.get('territory') or get_root('Territory')
doc.terms = frappe.db.get_value('Terms and Conditions', pos_profile.get('tc_name'), 'terms') or doc.terms or ''
doc.offline_pos_name = ''
def get_root(table):
root = frappe.db.sql(""" select name from `tab%(table)s` having
@@ -320,8 +321,7 @@ def make_invoice(doc_list={}, email_queue_list={}, customers_list={}):
si_doc.set_posting_time = 1
si_doc.customer = get_customer_id(doc)
si_doc.due_date = doc.get('posting_date')
submit_invoice(si_doc, name, doc)
name_list.append(name)
name_list = submit_invoice(si_doc, name, doc, name_list)
else:
name_list.append(name)
@@ -418,6 +418,7 @@ def make_contact(args,customer):
'link_doctype': 'Customer',
'link_name': customer
})
doc.flags.ignore_mandatory = True
doc.save(ignore_permissions=True)
def make_address(args, customer):
@@ -442,6 +443,7 @@ def make_address(args, customer):
address.is_primary_address = 1
address.is_shipping_address = 1
address.update(args)
address.flags.ignore_mandatory = True
address.save(ignore_permissions = True)
def make_email_queue(email_queue):
@@ -475,19 +477,33 @@ def validate_item(doc):
frappe.db.commit()
def submit_invoice(si_doc, name, doc):
def submit_invoice(si_doc, name, doc, name_list):
try:
si_doc.insert()
si_doc.submit()
frappe.db.commit()
name_list.append(name)
except Exception as e:
if frappe.message_log: frappe.message_log.pop()
frappe.db.rollback()
save_invoice(e, si_doc, name)
frappe.log_error(frappe.get_traceback())
name_list = save_invoice(doc, name, name_list)
def save_invoice(e, si_doc, name):
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
si_doc.docstatus = 0
si_doc.flags.ignore_mandatory = True
si_doc.due_date = si_doc.posting_date
si_doc.insert()
return name_list
def save_invoice(doc, name, name_list):
try:
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
si = frappe.new_doc('Sales Invoice')
si.update(doc)
si.set_posting_time = 1
si.customer = get_customer_id(doc)
si.due_date = doc.get('posting_date')
si.flags.ignore_mandatory = True
si.insert(ignore_permissions=True)
frappe.db.commit()
name_list.append(name)
except Exception:
frappe.log_error(frappe.get_traceback())
return name_list

View File

@@ -86,7 +86,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
this.make_payment_request, __("Make"));
}
if(!doc.subscription) {
cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __("Make"))
}
}
// Show buttons only when pos view is active
@@ -335,7 +339,7 @@ $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_
// ------------
cur_frm.cscript.hide_fields = function(doc) {
var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances',
'advances', 'sales_partner', 'commission_rate', 'total_commission', 'advances', 'from_date', 'to_date'];
'advances', 'advances', 'from_date', 'to_date'];
if(cint(doc.is_pos) == 1) {
hide_field(parent_fields);
@@ -516,6 +520,24 @@ frappe.ui.form.on('Sales Invoice', {
};
});
},
//When multiple companies are set up. in case company name is changed set default company address
company:function(frm){
if (frm.doc.company)
{
frappe.call({
method:"frappe.contacts.doctype.address.address.get_default_address",
args:{ doctype:'Company',name:frm.doc.company},
callback: function(r){
if (r.message){
frm.set_value("company_address",r.message)
}
else {
frm.set_value("company_address","")
}
}
})
}
},
project: function(frm){
frm.call({

View File

@@ -1670,36 +1670,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "net_total",
"fieldtype": "Currency",
"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": "Net Total",
"length": 0,
"no_copy": 0,
"options": "currency",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1731,6 +1701,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "net_total",
"fieldtype": "Currency",
"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": "Net Total",
"length": 0,
"no_copy": 0,
"options": "currency",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2337,6 +2337,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2463,6 +2494,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -4179,11 +4241,9 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "is_recurring",
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2 && !doc.__islocal",
"fieldname": "recurring_invoice",
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -4192,230 +4252,12 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Recurring Invoice",
"length": 0,
"no_copy": 0,
"options": "fa fa-time",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break11",
"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,
"label": "Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2",
"description": "",
"fieldname": "is_recurring",
"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": "Is Recurring",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"description": "",
"fieldname": "recurring_id",
"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": "Reference Document",
"length": 0,
"no_copy": 1,
"options": "Sales Invoice",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "recurring_type",
"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": "Frequency",
"length": 0,
"no_copy": 1,
"options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "repeat_on_day_of_month",
"fieldtype": "Int",
"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": "Repeat on Day of Month",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "end_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": "End Date",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"fieldname": "submit_on_creation",
"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": "Submit on creation",
"label": "Subscription Section",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4431,133 +4273,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "notify_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 by email",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name",
"description": "",
"fieldname": "notification_email_address",
"fieldtype": "Code",
"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": "Notification Email Address",
"length": 0,
"no_copy": 1,
"options": "Email",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name",
"fieldname": "recurring_print_format",
"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": "Recurring Print Format",
"length": 0,
"no_copy": 0,
"options": "Print Format",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break12",
"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,
"label": "This Document",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0,
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"depends_on": "",
"description": "",
"fieldname": "from_date",
"fieldtype": "Date",
@@ -4588,7 +4304,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"depends_on": "",
"description": "",
"fieldname": "to_date",
"fieldtype": "Date",
@@ -4619,10 +4335,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"description": "",
"fieldname": "next_date",
"fieldtype": "Date",
"fieldname": "column_break_140",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -4630,11 +4344,11 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next Date",
"length": 0,
"no_copy": 1,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -4644,6 +4358,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription",
"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": "Subscription",
"length": 0,
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -4688,7 +4433,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-07-07 13:05:37.469682",
"modified": "2017-10-24 12:46:48.331723",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -20,14 +20,15 @@ from erpnext.accounts.doctype.asset.depreciation \
from erpnext.stock.doctype.batch.batch import set_batch_nos
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos, get_delivery_note_serial_no
from erpnext.setup.doctype.company.company import update_company_current_month_sales
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
}
class SalesInvoice(SellingController):
def __init__(self, arg1, arg2=None):
super(SalesInvoice, self).__init__(arg1, arg2)
def __init__(self, *args, **kwargs):
super(SalesInvoice, self).__init__(*args, **kwargs)
self.status_updater = [{
'source_dt': 'Sales Invoice Item',
'target_field': 'billed_amt',
@@ -107,9 +108,9 @@ class SalesInvoice(SellingController):
def on_submit(self):
self.validate_pos_paid_amount()
if not self.recurring_id:
if not self.subscription:
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
self.company, self.base_grand_total, self)
self.company, self.base_grand_total, self)
self.check_prev_docstatus()
@@ -303,6 +304,7 @@ class SalesInvoice(SellingController):
self.account_for_change_amount = frappe.db.get_value('Company', self.company, 'default_cash_account')
if pos:
self.pos_profile = pos.name
if not for_validate and not self.customer:
self.customer = pos.customer
self.mode_of_payment = pos.mode_of_payment
@@ -313,7 +315,7 @@ class SalesInvoice(SellingController):
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account',
'write_off_account', 'write_off_cost_center'):
'write_off_account', 'write_off_cost_center', 'apply_discount_on'):
if (not for_validate) or (for_validate and not self.get(fieldname)):
self.set(fieldname, pos.get(fieldname))
@@ -625,6 +627,7 @@ class SalesInvoice(SellingController):
self.make_gle_for_change_amount(gl_entries)
self.make_write_off_gl_entry(gl_entries)
self.make_gle_for_rounding_adjustment(gl_entries)
return gl_entries
@@ -784,6 +787,21 @@ class SalesInvoice(SellingController):
}, write_off_account_currency)
)
def make_gle_for_rounding_adjustment(self, gl_entries):
if self.rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
gl_entries.append(
self.get_gl_dict({
"account": round_off_account,
"against": self.customer,
"credit_in_account_currency": self.rounding_adjustment,
"credit": self.base_rounding_adjustment,
"cost_center": round_off_cost_center,
}
))
def update_billing_status_in_dn(self, update_modified=True):
updated_delivery_notes = []
for d in self.get("items"):
@@ -799,7 +817,7 @@ class SalesInvoice(SellingController):
for dn in set(updated_delivery_notes):
frappe.get_doc("Delivery Note", dn).update_billing_percentage(update_modified=update_modified)
def on_recurring(self, reference_doc):
def on_recurring(self, reference_doc, subscription_doc):
for fieldname in ("c_form_applicable", "c_form_no", "write_off_amount"):
self.set(fieldname, reference_doc.get(fieldname))

View File

@@ -8,7 +8,8 @@ def get_data():
'Journal Entry': 'reference_name',
'Payment Entry': 'reference_name',
'Payment Request': 'reference_name',
'Sales Invoice': 'return_against'
'Sales Invoice': 'return_against',
'Subscription': 'reference_document',
},
'internal_links': {
'Sales Order': ['items', 'sales_order']
@@ -26,5 +27,9 @@ def get_data():
'label': _('Returns'),
'items': ['Sales Invoice']
},
{
'label': _('Subscription'),
'items': ['Subscription']
},
]
}

View File

@@ -3,8 +3,8 @@
from __future__ import unicode_literals
import frappe
import unittest, copy
from frappe.utils import nowdate, add_days, flt
import unittest, copy, time
from frappe.utils import nowdate, add_days, flt, cint
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@@ -215,12 +215,12 @@ class TestSalesInvoice(unittest.TestCase):
si.save()
# with inclusive tax and additional discount
self.assertEquals(si.net_total, 4298.24)
self.assertEquals(si.net_total, 4298.25)
self.assertEquals(si.grand_total, 4900.00)
def test_sales_invoice_discount_amount(self):
si = frappe.copy_doc(test_records[3])
si.discount_amount = 104.95
si.discount_amount = 104.94
si.append("taxes", {
"charge_type": "On Previous Row Amount",
"account_head": "_Test Account Service Tax - _TC",
@@ -285,7 +285,7 @@ class TestSalesInvoice(unittest.TestCase):
"_Test Account Customs Duty - _TC": [125, 116.35, 1585.40],
"_Test Account Shipping Charges - _TC": [100, 100, 1685.40],
"_Test Account Discount - _TC": [-180.33, -168.54, 1516.86],
"_Test Account Service Tax - _TC": [-18.03, -16.86, 1500]
"_Test Account Service Tax - _TC": [-18.03, -16.85, 1500.01]
}
for d in si.get("taxes"):
@@ -294,10 +294,12 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(si.base_grand_total, 1500)
self.assertEquals(si.grand_total, 1500)
self.assertEquals(si.rounding_adjustment, -0.01)
def test_discount_amount_gl_entry(self):
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
si = frappe.copy_doc(test_records[3])
si.discount_amount = 104.95
si.discount_amount = 104.94
si.append("taxes", {
"doctype": "Sales Taxes and Charges",
"charge_type": "On Previous Row Amount",
@@ -327,7 +329,8 @@ class TestSalesInvoice(unittest.TestCase):
[test_records[3]["taxes"][5]["account_head"], 0.0, 116.35],
[test_records[3]["taxes"][6]["account_head"], 0.0, 100],
[test_records[3]["taxes"][7]["account_head"], 168.54, 0.0],
["_Test Account Service Tax - _TC", 16.86, 0.0]
["_Test Account Service Tax - _TC", 16.85, 0.0],
["Round Off - _TC", 0.01, 0.0]
])
for gle in gl_entries:
@@ -423,13 +426,12 @@ class TestSalesInvoice(unittest.TestCase):
expected_values = {
"keys": ["price_list_rate", "discount_percentage", "rate", "amount",
"base_price_list_rate", "base_rate", "base_amount", "net_rate", "net_amount"],
"_Test Item Home Desktop 100": [62.5, 0, 62.5, 625.0, 62.5, 62.5, 625.0, 50, 499.98],
"_Test Item Home Desktop 200": [190.66, 0, 190.66, 953.3, 190.66, 190.66, 953.3, 150, 750],
"_Test Item Home Desktop 100": [62.5, 0, 62.5, 625.0, 62.5, 62.5, 625.0, 50, 499.97600115194473],
"_Test Item Home Desktop 200": [190.66, 0, 190.66, 953.3, 190.66, 190.66, 953.3, 150, 749.9968530500239],
}
# check if children are saved
self.assertEquals(len(si.get("items")),
len(expected_values)-1)
self.assertEquals(len(si.get("items")), len(expected_values)-1)
# check if item values are calculated
for d in si.get("items"):
@@ -437,28 +439,28 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(d.get(k), expected_values[d.item_code][i])
# check net total
self.assertEquals(si.base_net_total, 1249.98)
self.assertEquals(si.net_total, 1249.97)
self.assertEquals(si.total, 1578.3)
# check tax calculation
expected_values = {
"keys": ["tax_amount", "total"],
"_Test Account Excise Duty - _TC": [140, 1389.98],
"_Test Account Education Cess - _TC": [2.8, 1392.78],
"_Test Account S&H Education Cess - _TC": [1.4, 1394.18],
"_Test Account CST - _TC": [27.88, 1422.06],
"_Test Account VAT - _TC": [156.25, 1578.31],
"_Test Account Customs Duty - _TC": [125, 1703.31],
"_Test Account Shipping Charges - _TC": [100, 1803.31],
"_Test Account Discount - _TC": [-180.33, 1622.98]
"_Test Account Excise Duty - _TC": [140, 1389.97],
"_Test Account Education Cess - _TC": [2.8, 1392.77],
"_Test Account S&H Education Cess - _TC": [1.4, 1394.17],
"_Test Account CST - _TC": [27.88, 1422.05],
"_Test Account VAT - _TC": [156.25, 1578.30],
"_Test Account Customs Duty - _TC": [125, 1703.30],
"_Test Account Shipping Charges - _TC": [100, 1803.30],
"_Test Account Discount - _TC": [-180.33, 1622.97]
}
for d in si.get("taxes"):
for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.base_grand_total, 1622.98)
self.assertEquals(si.grand_total, 1622.98)
self.assertEquals(si.base_grand_total, 1622.97)
self.assertEquals(si.grand_total, 1622.97)
def test_sales_invoice_calculation_export_currency_with_tax_inclusive_price(self):
# prepare
@@ -486,7 +488,7 @@ class TestSalesInvoice(unittest.TestCase):
"base_rate": 2500,
"base_amount": 25000,
"net_rate": 40,
"net_amount": 399.98,
"net_amount": 399.9808009215558,
"base_net_rate": 2000,
"base_net_amount": 19999
},
@@ -500,7 +502,7 @@ class TestSalesInvoice(unittest.TestCase):
"base_rate": 7500,
"base_amount": 37500,
"net_rate": 118.01,
"net_amount": 590.05,
"net_amount": 590.0531205155963,
"base_net_rate": 5900.5,
"base_net_amount": 29502.5
}
@@ -536,8 +538,11 @@ class TestSalesInvoice(unittest.TestCase):
for i, k in enumerate(expected_values["keys"]):
self.assertEquals(d.get(k), expected_values[d.account_head][i])
self.assertEquals(si.base_grand_total, 60794.5)
self.assertEquals(si.grand_total, 1215.89)
self.assertEquals(si.base_grand_total, 60795)
self.assertEquals(si.grand_total, 1215.90)
self.assertEquals(si.rounding_adjustment, 0.01)
self.assertEquals(si.base_rounding_adjustment, 0.50)
def test_outstanding(self):
w = self.make()
@@ -660,6 +665,47 @@ class TestSalesInvoice(unittest.TestCase):
self.pos_gl_entry(si, pos, 330)
def test_make_pos_invoice_in_draft(self):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
from erpnext.stock.doctype.item.test_item import make_item
set_perpetual_inventory()
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
if allow_negative_stock:
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0)
make_pos_profile()
timestamp = cint(time.time())
item = make_item("_Test POS Item")
pos = copy.deepcopy(test_records[1])
pos['items'][0]['item_code'] = item.name
pos["is_pos"] = 1
pos["offline_pos_name"] = timestamp
pos["update_stock"] = 1
pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
invoice_data = [{timestamp: pos}]
si = make_invoice(invoice_data).get('invoice')
self.assertEquals(si[0], timestamp)
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp})
self.assertEquals(sales_invoice[0].docstatus, 0)
timestamp = cint(time.time())
pos["offline_pos_name"] = timestamp
invoice_data = [{timestamp: pos}]
si1 = make_invoice(invoice_data).get('invoice')
self.assertEquals(si1[0], timestamp)
sales_invoice1 = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp})
self.assertEquals(sales_invoice1[0].docstatus, 0)
if allow_negative_stock:
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 1)
def pos_gl_entry(self, si, pos, cash_amount):
# check stock ledger entries
sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
@@ -809,10 +855,6 @@ class TestSalesInvoice(unittest.TestCase):
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Entry Account`
where reference_name=%s""", si.name))
def test_recurring_invoice(self):
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
test_recurring_document(self, test_records)
def test_serialized(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
@@ -1083,7 +1125,7 @@ class TestSalesInvoice(unittest.TestCase):
si.items[0].price_list_rate = price_list_rate
si.items[0].margin_type = 'Percentage'
si.items[0].margin_rate_or_amount = 25
si.insert()
si.save()
self.assertEqual(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate))
def test_outstanding_amount_after_advance_jv_cancelation(self):
@@ -1091,6 +1133,7 @@ class TestSalesInvoice(unittest.TestCase):
import test_records as jv_test_records
jv = frappe.copy_doc(jv_test_records[0])
jv.accounts[0].is_advance = 'Yes'
jv.insert()
jv.submit()
@@ -1167,8 +1210,15 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total + si.total_advance, si.precision("outstanding_amount")))
def test_multiple_uom_in_selling(self):
si = frappe.copy_doc(test_records[1])
frappe.db.sql("""delete from `tabItem Price`
where price_list='_Test Price List' and item_code='_Test Item'""")
item_price = frappe.new_doc("Item Price")
item_price.price_list = "_Test Price List"
item_price.item_code = "_Test Item"
item_price.price_list_rate = 100
item_price.insert()
si = frappe.copy_doc(test_records[1])
si.items[0].uom = "_Test UOM 1"
si.items[0].conversion_factor = None
si.items[0].price_list_rate = None
@@ -1283,6 +1333,40 @@ class TestSalesInvoice(unittest.TestCase):
current_month_sales = frappe.db.get_value("Company", "_Test Company", "total_monthly_sales")
self.assertEqual(current_month_sales, existing_current_month_sales)
def test_rounding_adjustment(self):
si = create_sales_invoice(rate=24900, do_not_save=True)
for tax in ["Tax 1", "Tax2"]:
si.append("taxes", {
"charge_type": "On Net Total",
"account_head": "_Test Account Service Tax - _TC",
"description": tax,
"rate": 14,
"cost_center": "_Test Cost Center - _TC",
"included_in_print_rate": 1
})
si.save()
self.assertEqual(si.net_total, 19453.13)
self.assertEqual(si.grand_total, 24900)
self.assertEqual(si.total_taxes_and_charges, 5446.88)
self.assertEqual(si.rounding_adjustment, -0.01)
expected_values = dict((d[0], d) for d in [
[si.debit_to, 24900, 0.0],
["_Test Account Service Tax - _TC", 0.0, 5446.88],
["Sales - _TC", 0.0, 19453.13],
["Round Off - _TC", 0.01, 0.0]
])
gl_entries = frappe.db.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.name, as_dict=1)
for gle in gl_entries:
self.assertEquals(expected_values[gle.account][0], gle.account)
self.assertEquals(expected_values[gle.account][1], gle.debit)
self.assertEquals(expected_values[gle.account][2], gle.credit)
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)

View File

@@ -0,0 +1,52 @@
QUnit.module('Sales Invoice');
QUnit.test("test sales Invoice with payment request", function(assert) {
assert.expect(4);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Sales Invoice', [
{customer: 'Test Customer 1'},
{items: [
[
{'qty': 5},
{'item_code': 'Test Product 1'},
]
]},
{update_stock:1},
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
// grand_total Calculated
assert.ok(cur_frm.doc.grand_total==590, "Grad Total correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(2),
() => frappe.tests.click_button('Close'),
() => frappe.tests.click_button('Make'),
() => frappe.tests.click_link('Payment Request'),
() => frappe.timeout(0.2),
() => { cur_frm.set_value('print_format','GST Tax Invoice');},
() => { cur_frm.set_value('email_to','test@gmail.com');},
() => cur_frm.save(),
() => {
// get payment details
assert.ok(cur_frm.doc.grand_total==590, "grand total Correct");
},
() => done()
]);
});

View File

@@ -0,0 +1,45 @@
QUnit.module('Sales Invoice');
QUnit.test("test sales Invoice with serialize item", function(assert) {
assert.expect(5);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Sales Invoice', [
{customer: 'Test Customer 1'},
{items: [
[
{'qty': 2},
{'item_code': 'Test Product 4'},
]
]},
{update_stock:1},
{customer_address: 'Test1-Billing'},
{shipping_address_name: 'Test1-Shipping'},
{contact_person: 'Contact 1-Test Customer 1'},
{taxes_and_charges: 'TEST In State GST'},
{tc_name: 'Test Term 1'},
{terms: 'This is Test'}
]);
},
() => cur_frm.save(),
() => {
// get_item_details
assert.ok(cur_frm.doc.items[0].item_name=='Test Product 4', "Item name correct");
// get tax details
assert.ok(cur_frm.doc.taxes_and_charges=='TEST In State GST', "Tax details correct");
// get tax account head details
assert.ok(cur_frm.doc.taxes[0].account_head=='CGST - '+frappe.get_abbr(frappe.defaults.get_default('Company')), " Account Head abbr correct");
// get batch number
assert.ok(cur_frm.doc.items[0].batch_no=='TEST-BATCH-001', " Batch Details correct");
// grand_total Calculated
assert.ok(cur_frm.doc.grand_total==218, "Grad Total correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => done()
]);
});

View File

@@ -699,7 +699,7 @@
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "2",
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -2166,7 +2166,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-07-17 17:54:48.246507",
"modified": "2017-09-27 08:31:37.827893",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -54,13 +54,15 @@ class ShippingRule(Document):
d.idx = i + 1
def validate_overlapping_shipping_rule_conditions(self):
def overlap_exists_between((x1, x2), (y1, y2)):
def overlap_exists_between(num_range1, num_range2):
"""
(x1, x2) and (y1, y2) are two ranges
if condition x = 100 to 300
then condition y can only be like 50 to 99 or 301 to 400
num_range1 and num_range2 are two ranges
ranges are represented as a tuple e.g. range 100 to 300 is represented as (100, 300)
if condition num_range1 = 100 to 300
then condition num_range2 can only be like 50 to 99 or 301 to 400
hence, non-overlapping condition = (x1 <= x2 < y1 <= y2) or (y1 <= y2 < x1 <= x2)
"""
(x1, x2), (y1, y2) = num_range1, num_range2
separate = (x1 <= x2 <= y1 <= y2) or (y1 <= y2 <= x1 <= x2)
return (not separate)

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Subscription', {
setup: function(frm) {
frm.fields_dict['reference_doctype'].get_query = function(doc) {
return {
query: "erpnext.accounts.doctype.subscription.subscription.subscription_doctype_query"
};
};
frm.fields_dict['reference_document'].get_query = function() {
return {
filters: {
"docstatus": 1,
"subscription": ''
}
};
};
frm.fields_dict['print_format'].get_query = function() {
return {
filters: {
"doc_type": frm.doc.reference_doctype
}
};
};
},
refresh: function(frm) {
if(frm.doc.docstatus == 1) {
let label = __('View {0}', [frm.doc.reference_doctype]);
frm.add_custom_button(__(label),
function() {
frappe.route_options = {
"subscription": frm.doc.name,
};
frappe.set_route("List", frm.doc.reference_doctype);
}
);
if(frm.doc.status != 'Stopped') {
frm.add_custom_button(__("Stop"),
function() {
frm.events.stop_resume_subscription(frm, "Stopped");
}
);
}
if(frm.doc.status == 'Stopped') {
frm.add_custom_button(__("Resume"),
function() {
frm.events.stop_resume_subscription(frm, "Resumed");
}
);
}
}
},
stop_resume_subscription: function(frm, status) {
frappe.call({
method: "erpnext.accounts.doctype.subscription.subscription.stop_resume_subscription",
args: {
subscription: frm.doc.name,
status: status
},
callback: function(r) {
if(r.message) {
frm.set_value("status", r.message);
frm.reload_doc();
}
}
});
}
});

View File

@@ -0,0 +1,865 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
"beta": 0,
"creation": "2017-07-18 17:50:43.967266",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_1",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "naming_series",
"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": "Series",
"length": 0,
"no_copy": 0,
"options": "SUB-",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_doctype",
"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": "Reference Doctype",
"length": 0,
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "reference_document",
"fieldtype": "Dynamic 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": "Reference Document",
"length": 0,
"no_copy": 1,
"options": "reference_doctype",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "start_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": "Start 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": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "end_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": "End 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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "submit_on_creation",
"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": "Submit on Creation",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"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": "Disabled",
"length": 0,
"no_copy": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_10",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "frequency",
"fieldtype": "Select",
"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": "Frequency",
"length": 0,
"no_copy": 0,
"options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf-yearly\nYearly",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_13",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval: in_list([\"Monthly\", \"Quarterly\", \"Yearly\"], doc.frequency)",
"fieldname": "repeat_on_day",
"fieldtype": "Int",
"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": "Repeat on Day",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "next_schedule_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": "Next Schedule Date",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "notification",
"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": "Notification",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "notify_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 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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval: doc.notify_by_email",
"description": "To add dynamic subject, use jinja tags like\n\n<div><pre><code>New {{ doc.doctype }} #{{ doc.name }}</code></pre></div>",
"fieldname": "subject",
"fieldtype": "Data",
"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": "Subject",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_17",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "notify_by_email",
"fieldname": "recipients",
"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": "Recipients",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "notify_by_email",
"fieldname": "print_format",
"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": "Print Format",
"length": 0,
"no_copy": 0,
"options": "Print Format",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"depends_on": "eval:doc.notify_by_email",
"fieldname": "section_break_20",
"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": "Message",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Please find attached {{ doc.doctype }} #{{ doc.name }}",
"fieldname": "message",
"fieldtype": "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": "Message",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"depends_on": "eval: !doc.__islocal",
"fieldname": "section_break_16",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Draft",
"fieldname": "status",
"fieldtype": "Select",
"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": "Status",
"length": 0,
"no_copy": 0,
"options": "\nDraft\nStopped\nSubmitted\nCancelled\nCompleted",
"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,
"unique": 0
},
{
"allow_bulk_edit": 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": "Subscription",
"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,
"unique": 0
}
],
"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": "2017-10-23 18:28:08.966403",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"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,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "reference_document",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "reference_document",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -0,0 +1,313 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
import calendar
from frappe import _
from frappe.desk.form import assign_to
from frappe.utils.jinja import validate_template
from dateutil.relativedelta import relativedelta
from frappe.utils.user import get_system_managers
from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day
from frappe.model.document import Document
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
class Subscription(Document):
def validate(self):
self.update_status()
self.validate_reference_doctype()
self.validate_dates()
self.validate_next_schedule_date()
self.validate_email_id()
validate_template(self.subject or "")
validate_template(self.message or "")
def before_submit(self):
if not self.next_schedule_date:
self.next_schedule_date = get_next_schedule_date(self.start_date,
self.frequency, self.repeat_on_day)
def on_submit(self):
self.update_subscription_id()
def on_update_after_submit(self):
self.validate_dates()
self.set_next_schedule_date()
def before_cancel(self):
self.unlink_subscription_id()
self.next_schedule_date = None
def unlink_subscription_id(self):
frappe.db.sql("update `tab{0}` set subscription = null where subscription=%s"
.format(self.reference_doctype), self.name)
def validate_reference_doctype(self):
if not frappe.get_meta(self.reference_doctype).has_field('subscription'):
frappe.throw(_("Add custom field Subscription in the doctype {0}").format(self.reference_doctype))
def validate_dates(self):
if self.end_date and getdate(self.start_date) > getdate(self.end_date):
frappe.throw(_("End date must be greater than start date"))
def validate_next_schedule_date(self):
if self.repeat_on_day and self.next_schedule_date:
next_date = getdate(self.next_schedule_date)
if next_date.day != self.repeat_on_day:
# if the repeat day is the last day of the month (31)
# and the current month does not have as many days,
# then the last day of the current month is a valid date
lastday = calendar.monthrange(next_date.year, next_date.month)[1]
if self.repeat_on_day < lastday:
# the specified day of the month is not same as the day specified
# or the last day of the month
frappe.throw(_("Next Date's day and Repeat on Day of Month must be equal"))
def validate_email_id(self):
if self.notify_by_email:
if self.recipients:
email_list = split_emails(self.recipients.replace("\n", ""))
from frappe.utils import validate_email_add
for email in email_list:
if not validate_email_add(email):
frappe.throw(_("{0} is an invalid email address in 'Recipients'").format(email))
else:
frappe.throw(_("'Recipients' not specified"))
def set_next_schedule_date(self):
if self.repeat_on_day:
self.next_schedule_date = get_next_date(self.next_schedule_date, 0, self.repeat_on_day)
def update_subscription_id(self):
frappe.db.set_value(self.reference_doctype, self.reference_document, "subscription", self.name)
def update_status(self, status=None):
self.status = {
'0': 'Draft',
'1': 'Submitted',
'2': 'Cancelled'
}[cstr(self.docstatus or 0)]
if status and status != 'Resumed':
self.status = status
def get_next_schedule_date(start_date, frequency, repeat_on_day):
mcount = month_map.get(frequency)
if mcount:
next_date = get_next_date(start_date, mcount, repeat_on_day)
else:
days = 7 if frequency == 'Weekly' else 1
next_date = add_days(start_date, days)
return next_date
def make_subscription_entry(date=None):
date = date or today()
for data in get_subscription_entries(date):
schedule_date = getdate(data.next_schedule_date)
while schedule_date <= getdate(today()):
create_documents(data, schedule_date)
schedule_date = get_next_schedule_date(schedule_date,
data.frequency, data.repeat_on_day)
if schedule_date and not frappe.db.get_value('Subscription', data.name, 'disabled'):
frappe.db.set_value('Subscription', data.name, 'next_schedule_date', schedule_date)
def get_subscription_entries(date):
return frappe.db.sql(""" select * from `tabSubscription`
where docstatus = 1 and next_schedule_date <=%s
and reference_document is not null and reference_document != ''
and next_schedule_date <= ifnull(end_date, '2199-12-31')
and ifnull(disabled, 0) = 0 and status != 'Stopped' """, (date), as_dict=1)
def create_documents(data, schedule_date):
try:
doc = make_new_document(data, schedule_date)
if data.notify_by_email and data.recipients:
print_format = data.print_format or "Standard"
send_notification(doc, data, print_format=print_format)
frappe.db.commit()
except Exception:
frappe.db.rollback()
frappe.db.begin()
frappe.log_error(frappe.get_traceback())
disable_subscription(data)
frappe.db.commit()
if data.reference_document and not frappe.flags.in_test:
notify_error_to_user(data)
def disable_subscription(data):
subscription = frappe.get_doc('Subscription', data.name)
subscription.db_set('disabled', 1)
def notify_error_to_user(data):
party = ''
party_type = ''
if data.reference_doctype in ['Sales Order', 'Sales Invoice', 'Delivery Note']:
party_type = 'customer'
elif data.reference_doctype in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']:
party_type = 'supplier'
if party_type:
party = frappe.db.get_value(data.reference_doctype, data.reference_document, party_type)
notify_errors(data.reference_document, data.reference_doctype, party, data.owner, data.name)
def make_new_document(args, schedule_date):
doc = frappe.get_doc(args.reference_doctype, args.reference_document)
new_doc = frappe.copy_doc(doc, ignore_no_copy=False)
update_doc(new_doc, doc , args, schedule_date)
new_doc.insert(ignore_permissions=True)
if args.submit_on_creation:
new_doc.submit()
return new_doc
def update_doc(new_document, reference_doc, args, schedule_date):
new_document.docstatus = 0
if new_document.meta.get_field('set_posting_time'):
new_document.set('set_posting_time', 1)
mcount = month_map.get(args.frequency)
if new_document.meta.get_field('subscription'):
new_document.set('subscription', args.name)
for fieldname in ['naming_series', 'ignore_pricing_rule', 'posting_time'
'select_print_heading', 'remarks', 'owner']:
if new_document.meta.get_field(fieldname):
new_document.set(fieldname, reference_doc.get(fieldname))
# copy item fields
if new_document.meta.get_field('items'):
for i, item in enumerate(new_document.items):
for fieldname in ("page_break",):
item.set(fieldname, reference_doc.items[i].get(fieldname))
for data in new_document.meta.fields:
if data.fieldtype == 'Date' and data.reqd:
new_document.set(data.fieldname, schedule_date)
set_subscription_period(args, mcount, new_document)
new_document.run_method("on_recurring", reference_doc=reference_doc, subscription_doc=args)
def set_subscription_period(args, mcount, new_document):
if mcount and new_document.meta.get_field('from_date') and new_document.meta.get_field('to_date'):
last_ref_doc = frappe.db.sql("""
select name, from_date, to_date
from `tab{0}`
where subscription=%s and docstatus < 2
order by creation desc
limit 1
""".format(args.reference_doctype), args.name, as_dict=1)
if not last_ref_doc:
return
from_date = get_next_date(last_ref_doc[0].from_date, mcount)
if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and \
(cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date)):
to_date = get_last_day(get_next_date(last_ref_doc[0].to_date, mcount))
else:
to_date = get_next_date(last_ref_doc[0].to_date, mcount)
new_document.set('from_date', from_date)
new_document.set('to_date', to_date)
def get_next_date(dt, mcount, day=None):
dt = getdate(dt)
dt += relativedelta(months=mcount, day=day)
return dt
def send_notification(new_rv, subscription_doc, print_format='Standard'):
"""Notify concerned persons about recurring document generation"""
print_format = print_format
if not subscription_doc.subject:
subject = _("New {0}: #{1}").format(new_rv.doctype, new_rv.name)
elif "{" in subscription_doc.subject:
subject = frappe.render_template(subscription_doc.subject, {'doc': new_rv})
if not subscription_doc.message:
message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name)
elif "{" in subscription_doc.message:
message = frappe.render_template(subscription_doc.message, {'doc': new_rv})
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name,
file_name=new_rv.name, print_format=print_format)]
frappe.sendmail(subscription_doc.recipients,
subject=subject, message=message, attachments=attachments)
def notify_errors(doc, doctype, party, owner, name):
recipients = get_system_managers(only_name=True)
frappe.sendmail(recipients + [frappe.db.get_value("User", owner, "email")],
subject=_("[Urgent] Error while creating recurring %s for %s" % (doctype, doc)),
message = frappe.get_template("templates/emails/recurring_document_failed.html").render({
"type": _(doctype),
"name": doc,
"party": party or "",
"subscription": name
}))
assign_task_to_owner(name, "Recurring Documents Failed", recipients)
def assign_task_to_owner(name, msg, users):
for d in users:
args = {
'doctype' : 'Subscription',
'assign_to' : d,
'name' : name,
'description' : msg,
'priority' : 'High'
}
assign_to.add(args)
@frappe.whitelist()
def make_subscription(doctype, docname):
doc = frappe.new_doc('Subscription')
reference_doc = frappe.get_doc(doctype, docname)
doc.reference_doctype = doctype
doc.reference_document = docname
doc.start_date = reference_doc.get('posting_date') or reference_doc.get('transaction_date')
return doc
@frappe.whitelist()
def stop_resume_subscription(subscription, status):
doc = frappe.get_doc('Subscription', subscription)
frappe.msgprint(_("Subscription has been {0}").format(status))
if status == 'Resumed':
doc.next_schedule_date = get_next_schedule_date(today(),
doc.frequency, doc.repeat_on_day)
doc.update_status(status)
doc.save()
return doc.status
def subscription_doctype_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select parent from `tabDocField`
where fieldname = 'subscription'
and parent like %(txt)s
order by
if(locate(%(_txt)s, parent), locate(%(_txt)s, parent), 99999),
parent
limit %(start)s, %(page_len)s""".format(**{
'key': searchfield,
}), {
'txt': "%%%s%%" % txt,
'_txt': txt.replace("%", ""),
'start': start,
'page_len': page_len
})

View File

@@ -0,0 +1,16 @@
frappe.listview_settings['Subscription'] = {
add_fields: ["next_schedule_date"],
get_indicator: function(doc) {
if(doc.disabled) {
return [__("Disabled"), "red"];
} else if(doc.next_schedule_date >= frappe.datetime.get_today() && doc.status != 'Stopped') {
return [__("Active"), "green"];
} else if(doc.docstatus === 0) {
return [__("Draft"), "red", "docstatus,=,0"];
} else if(doc.status === 'Stopped') {
return [__("Stopped"), "red"];
} else {
return [__("Expired"), "darkgrey"];
}
}
};

View File

@@ -0,0 +1,32 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Subscription", function (assert) {
assert.expect(4);
let done = assert.async();
frappe.run_serially([
// insert a new Subscription
() => {
return frappe.tests.make("Subscription", [
{reference_doctype: 'Sales Invoice'},
{reference_document: 'SINV-00004'},
{start_date: frappe.datetime.month_start()},
{end_date: frappe.datetime.month_end()},
{frequency: 'Weekly'}
]);
},
() => cur_frm.savesubmit(),
() => frappe.timeout(1),
() => frappe.click_button('Yes'),
() => frappe.timeout(2),
() => {
assert.ok(cur_frm.doc.frequency.includes("Weekly"), "Set frequency Weekly");
assert.ok(cur_frm.doc.reference_doctype.includes("Sales Invoice"), "Set base doctype Sales Invoice");
assert.equal(cur_frm.doc.docstatus, 1, "Submitted subscription");
assert.equal(cur_frm.doc.next_schedule_date,
frappe.datetime.add_days(frappe.datetime.get_today(), 7), "Set schedule date");
},
() => done()
]);
});

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from frappe.utils import today, add_days, getdate
from erpnext.accounts.utils import get_fiscal_year
from erpnext.accounts.report.financial_statements import get_months
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.accounts.doctype.subscription.subscription import make_subscription_entry
class TestSubscription(unittest.TestCase):
def test_daily_subscription(self):
qo = frappe.copy_doc(quotation_records[0])
qo.submit()
doc = make_subscription(reference_document=qo.name)
self.assertEquals(doc.next_schedule_date, today())
make_subscription_entry()
frappe.db.commit()
quotation = frappe.get_doc(doc.reference_doctype, doc.reference_document)
self.assertEquals(quotation.subscription, doc.name)
new_quotation = frappe.db.get_value('Quotation',
{'subscription': doc.name, 'name': ('!=', quotation.name)}, 'name')
new_quotation = frappe.get_doc('Quotation', new_quotation)
for fieldname in ['customer', 'company', 'order_type', 'total', 'net_total']:
self.assertEquals(quotation.get(fieldname), new_quotation.get(fieldname))
for fieldname in ['item_code', 'qty', 'rate', 'amount']:
self.assertEquals(quotation.items[0].get(fieldname),
new_quotation.items[0].get(fieldname))
def test_monthly_subscription_for_so(self):
current_fiscal_year = get_fiscal_year(today(), as_dict=True)
start_date = current_fiscal_year.year_start_date
end_date = current_fiscal_year.year_end_date
for doctype in ['Sales Order', 'Sales Invoice']:
if doctype == 'Sales Invoice':
docname = create_sales_invoice(posting_date=start_date)
else:
docname = make_sales_order()
self.monthly_subscription(doctype, docname.name, start_date, end_date)
def monthly_subscription(self, doctype, docname, start_date, end_date):
doc = make_subscription(reference_doctype=doctype, frequency = 'Monthly',
reference_document = docname, start_date=start_date, end_date=end_date)
doc.disabled = 1
doc.save()
frappe.db.commit()
make_subscription_entry()
docnames = frappe.get_all(doc.reference_doctype, {'subscription': doc.name})
self.assertEquals(len(docnames), 1)
doc = frappe.get_doc('Subscription', doc.name)
doc.disabled = 0
doc.save()
months = get_months(getdate(start_date), getdate(today()))
make_subscription_entry()
docnames = frappe.get_all(doc.reference_doctype, {'subscription': doc.name})
self.assertEquals(len(docnames), months)
quotation_records = frappe.get_test_records('Quotation')
def make_subscription(**args):
args = frappe._dict(args)
doc = frappe.get_doc({
'doctype': 'Subscription',
'reference_doctype': args.reference_doctype or 'Quotation',
'reference_document': args.reference_document or \
frappe.db.get_value('Quotation', {'docstatus': 1}, 'name'),
'frequency': args.frequency or 'Daily',
'start_date': args.start_date or add_days(today(), -1),
'end_date': args.end_date or add_days(today(), 1),
'submit_on_creation': args.submit_on_creation or 0
}).insert(ignore_permissions=True)
if not args.do_not_submit:
doc.submit()
return doc

View File

@@ -8,6 +8,7 @@ from frappe import _
from frappe.model.document import Document
from frappe.utils import cstr, cint
from frappe.contacts.doctype.address.address import get_default_address
from frappe.utils.nestedset import get_root_of
from erpnext.setup.doctype.customer_group.customer_group import get_parent_customer_groups
class IncorrectCustomerGroup(frappe.ValidationError): pass
@@ -135,7 +136,8 @@ def get_tax_template(posting_date, args):
for key, value in args.iteritems():
if key=="use_for_shopping_cart":
conditions.append("use_for_shopping_cart = {0}".format(1 if value else 0))
if key == 'customer_group' and value:
if key == 'customer_group':
if not value: value = get_root_of("Customer Group")
customer_group_condition = get_customer_group_condition(value)
conditions.append("ifnull({0}, '') in ('', {1})".format(key, customer_group_condition))
else:

View File

@@ -11,7 +11,10 @@ test_records = frappe.get_test_records('Tax Rule')
class TestTaxRule(unittest.TestCase):
def setUp(self):
frappe.db.sql("delete from `tabTax Rule` where use_for_shopping_cart <> 1")
frappe.db.sql("delete from `tabTax Rule`")
def tearDown(self):
frappe.db.sql("delete from `tabTax Rule`")
def test_conflict(self):
tax_rule1 = make_tax_rule(customer= "_Test Customer",
@@ -39,7 +42,7 @@ class TestTaxRule(unittest.TestCase):
sales_tax_template = "_Test Sales Taxes and Charges Template", priority = 1, from_date = "2015-01-01")
tax_rule1.save()
self.assertEquals(get_tax_template("2015-01-01", {"customer_group" : "Commercial"}),
self.assertEquals(get_tax_template("2015-01-01", {"customer_group" : "Commercial", "use_for_shopping_cart":0}),
"_Test Sales Taxes and Charges Template")
def test_conflict_with_overlapping_dates(self):

View File

@@ -136,14 +136,7 @@ def round_off_debit_credit(gl_map):
make_round_off_gle(gl_map, debit_credit_diff)
def make_round_off_gle(gl_map, debit_credit_diff):
round_off_account, round_off_cost_center = frappe.db.get_value("Company", gl_map[0].company,
["round_off_account", "round_off_cost_center"]) or [None, None]
if not round_off_account:
frappe.throw(_("Please mention Round Off Account in Company"))
if not round_off_cost_center:
frappe.throw(_("Please mention Round Off Cost Center in Company"))
round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(gl_map[0].company)
round_off_gle = frappe._dict()
for k in ["voucher_type", "voucher_no", "company",
@@ -165,6 +158,17 @@ def make_round_off_gle(gl_map, debit_credit_diff):
gl_map.append(round_off_gle)
def get_round_off_account_and_cost_center(company):
round_off_account, round_off_cost_center = frappe.db.get_value("Company", company,
["round_off_account", "round_off_cost_center"]) or [None, None]
if not round_off_account:
frappe.throw(_("Please mention Round Off Account in Company"))
if not round_off_cost_center:
frappe.throw(_("Please mention Round Off Cost Center in Company"))
return round_off_account, round_off_cost_center
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
adv_adj=False, update_outstanding="Yes"):

View File

@@ -8,7 +8,16 @@ frappe.pages['pos'].on_page_load = function (wrapper) {
single_column: true
});
wrapper.pos = new erpnext.pos.PointOfSale(wrapper)
frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'is_online', (r) => {
if (r && r.use_pos_in_offline_mode && cint(r.use_pos_in_offline_mode)) {
// offline
wrapper.pos = new erpnext.pos.PointOfSale(wrapper);
cur_pos = wrapper.pos;
} else {
// online
frappe.set_route('point-of-sale');
}
});
}
frappe.pages['pos'].refresh = function (wrapper) {
@@ -75,6 +84,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.get_data_from_server(function () {
me.make_control();
me.create_new();
me.make();
});
},
@@ -104,6 +114,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
});
this.page.add_menu_item(__("Sync Offline Invoices"), function () {
me.freeze_screen = true;
me.sync_sales_invoice()
});
@@ -168,41 +179,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
},
dialog_actions: function () {
var me = this;
$(this.list_body).find('.list-select-all').click(function () {
me.removed_items = [];
$(me.list_body).find('.list-delete').prop("checked", $(this).is(":checked"))
if ($(this).is(":checked")) {
$.each(me.si_docs, function (index, data) {
for (key in data) {
me.removed_items.push(key)
}
})
}
me.toggle_delete_button();
})
$(this.list_body).find('.list-delete').click(function () {
me.name = $(this).parent().parent().attr('invoice-name');
if ($(this).is(":checked")) {
me.removed_items.push(me.name);
} else {
me.removed_items.pop(me.name)
}
me.toggle_delete_button();
})
},
edit_record: function () {
var me = this;
doc_data = this.get_invoice_doc(this.si_docs);
if (doc_data) {
this.frm.doc = doc_data[0][this.name];
this.frm.doc = doc_data[0][this.frm.doc.offline_pos_name];
this.set_missing_values();
this.refresh(false);
this.toggle_input_field();
@@ -215,16 +197,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.validate_list()
this.remove_doc_from_localstorage()
this.update_localstorage();
// this.dialog_actions();
this.toggle_delete_button();
},
validate_list: function() {
var me = this;
this.si_docs = this.get_submitted_invoice()
$.each(this.removed_items, function(index, name){
$.each(this.removed_items, function(index, pos_name){
$.each(me.si_docs, function(key, data){
if(me.si_docs[key][name] && me.si_docs[key][name].offline_pos_name == name ){
if(me.si_docs[key][pos_name] && me.si_docs[key][pos_name].offline_pos_name == pos_name ){
frappe.throw(__("Submitted orders can not be deleted"))
}
})
@@ -260,9 +241,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.calculate_outstanding_amount();
}
if (this.frm.doc.customer) {
this.party_field.$input.val(this.frm.doc.customer);
}
this.set_customer_value_in_party_field();
if (!this.frm.doc.write_off_account) {
this.frm.doc.write_off_account = doc.write_off_account
@@ -273,13 +252,19 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
},
set_customer_value_in_party_field: function() {
if (this.frm.doc.customer) {
this.party_field.$input.val(this.frm.doc.customer);
}
},
get_invoice_doc: function (si_docs) {
var me = this;
this.si_docs = this.get_doc_from_localstorage();
return $.grep(this.si_docs, function (data) {
for (key in data) {
return key == me.name
return key == me.frm.doc.offline_pos_name;
}
})
},
@@ -333,7 +318,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
create_new: function () {
var me = this;
this.frm = {}
this.name = null;
this.load_data(true);
this.setup();
this.set_default_customer()
@@ -347,6 +331,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
if (load_doc) {
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
this.frm.doc.offline_pos_name = null;
}
$.each(this.meta, function (i, data) {
@@ -368,7 +353,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
setup: function () {
this.make();
this.set_primary_action();
this.party_field.$input.attr('disabled', false);
if(this.selected_row) {
@@ -426,11 +410,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
});
this.serach_item.make_input();
this.serach_item.$input.on("keyup", function () {
setTimeout(function () {
me.items = me.get_items();
me.make_item_list();
}, 1000);
this.serach_item.$input.on("keypress", function (event) {
clearTimeout(me.last_search_timeout);
me.last_search_timeout = setTimeout(() => {
if((me.serach_item.$input.val() != "") || (event.which == 13)) {
me.items = me.get_items();
me.make_item_list();
}
}, 400);
});
this.search_item_group = this.wrapper.find('.search-item-group');
@@ -610,6 +599,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
// this.list_customers.empty();
this.si_docs = this.get_doc_from_localstorage();
if (!this.si_docs.length) {
this.list_customers.find('.list-customers-table').html("");
return;
}
@@ -636,7 +626,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
me.list_customers_btn.toggleClass("view_customer");
me.pos_bill.show();
me.list_customers_btn.show();
me.name = $(this).parents().attr('invoice-name')
me.frm.doc.offline_pos_name = $(this).parents().attr('invoice-name')
me.edit_record();
})
@@ -656,11 +646,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
});
$(this.wrapper).find('.list-delete').click(function () {
me.name = $(this).parent().parent().attr('invoice-name');
me.frm.doc.offline_pos_name = $(this).parent().parent().attr('invoice-name');
if ($(this).is(":checked")) {
me.removed_items.push(me.name);
me.removed_items.push(me.frm.doc.offline_pos_name);
} else {
me.removed_items.pop(me.name)
me.removed_items.pop(me.frm.doc.offline_pos_name)
}
me.toggle_delete_button();
@@ -681,6 +671,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
set_focus: function () {
if (this.default_customer || this.frm.doc.customer) {
this.set_customer_value_in_party_field();
this.serach_item.$input.focus();
} else {
this.party_field.$input.focus();
@@ -727,14 +718,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
input = input.toLowerCase();
item = this.get_item(item.value);
var searchtext =
Object.keys(item)
.filter(key => ['customer_name', 'customer_group', 'value', 'label', 'email_id', 'phone', 'mobile_no'].includes(key))
.map(key => item[key])
.join(" ")
.toLowerCase();
return searchtext.includes(input)
result = item ? item.searchtext.includes(input) : '';
if(!result) {
me.prepare_customer_mapper(input);
} else {
return result;
}
},
item: function (item, input) {
var d = this.get_item(item.value);
@@ -755,6 +744,9 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.party_field.$input
.on('input', function (e) {
if(me.customers_mapper.length <= 1) {
me.prepare_customer_mapper(e.target.value);
}
me.party_field.awesomeplete.list = me.customers_mapper;
})
.on('awesomplete-select', function (e) {
@@ -795,20 +787,56 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
});
},
prepare_customer_mapper: function() {
prepare_customer_mapper: function(key) {
var me = this;
var customer_data = '';
this.customers_mapper = this.customers.map(function (c) {
contact = me.contacts[c.name];
return {
label: c.name,
value: c.name,
customer_name: c.customer_name,
customer_group: c.customer_group,
territory: c.territory,
phone: contact ? contact["phone"] : '',
mobile_no: contact ? contact["mobile_no"] : '',
email_id: contact ? contact["email_id"] : ''
if (key) {
key = key.toLowerCase().trim();
var re = new RegExp('%', 'g');
var reg = new RegExp(key.replace(re, '\\w*\\s*[a-zA-Z0-9]*'));
customer_data = $.grep(this.customers, function(data) {
contact = me.contacts[data.name];
if(reg.test(data.name.toLowerCase())
|| reg.test(data.customer_name.toLowerCase())
|| (contact && reg.test(contact["mobile_no"]))
|| (contact && reg.test(contact["phone"]))
|| (data.customer_group && reg.test(data.customer_group.toLowerCase()))){
return data;
}
})
} else {
customer_data = this.customers;
}
this.customers_mapper = [];
customer_data.forEach(function (c, index) {
if(index < 30) {
contact = me.contacts[c.name];
if(contact && !c['phone']) {
c["phone"] = contact["phone"];
c["email_id"] = contact["email_id"];
c["mobile_no"] = contact["mobile_no"];
}
me.customers_mapper.push({
label: c.name,
value: c.name,
customer_name: c.customer_name,
customer_group: c.customer_group,
territory: c.territory,
phone: contact ? contact["phone"] : '',
mobile_no: contact ? contact["mobile_no"] : '',
email_id: contact ? contact["email_id"] : '',
searchtext: ['customer_name', 'customer_group', 'name', 'value',
'label', 'email_id', 'phone', 'mobile_no']
.map(key => c[key]).join(' ')
.toLowerCase()
});
} else {
return;
}
});
@@ -1284,6 +1312,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.wrapper.find('input.discount-percentage').on("change", function () {
me.frm.doc.additional_discount_percentage = flt($(this).val(), precision("additional_discount_percentage"));
if(me.frm.doc.additional_discount_percentage && me.frm.doc.discount_amount) {
// Reset discount amount
me.frm.doc.discount_amount = 0;
}
var total = me.frm.doc.grand_total
if (me.frm.doc.apply_discount_on == 'Net Total') {
@@ -1291,15 +1325,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
me.frm.doc.discount_amount = flt(total * flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount"));
me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount)
me.refresh();
me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount)
});
this.wrapper.find('input.discount-amount').on("change", function () {
me.frm.doc.discount_amount = flt($(this).val(), precision("discount_amount"));
me.frm.doc.additional_discount_percentage = 0.0;
me.wrapper.find('input.discount-percentage').val(0);
me.refresh();
me.wrapper.find('input.discount-percentage').val(0);
});
},
@@ -1372,7 +1406,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
update_paid_amount_status: function (update_paid_amount) {
if (this.name) {
if (this.frm.doc.offline_pos_name) {
update_paid_amount = update_paid_amount ? false : true;
}
@@ -1460,6 +1494,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
var me = this;
this.wrapper.find(".net-total").text(format_currency(me.frm.doc.total, me.frm.doc.currency));
this.wrapper.find(".grand-total").text(format_currency(me.frm.doc.grand_total, me.frm.doc.currency));
this.wrapper.find('input.discount-percentage').val(this.frm.doc.additional_discount_percentage);
this.wrapper.find('input.discount-amount').val(this.frm.doc.discount_amount);
},
set_primary_action: function () {
@@ -1578,18 +1614,17 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
create_invoice: function () {
var me = this;
var invoice_data = {}
var invoice_data = {};
this.si_docs = this.get_doc_from_localstorage();
if (this.name) {
this.update_invoice()
if (this.frm.doc.offline_pos_name) {
this.update_invoice();
} else {
this.name = $.now();
this.frm.doc.offline_pos_name = this.name;
this.frm.doc.offline_pos_name = $.now();
this.frm.doc.posting_date = frappe.datetime.get_today();
this.frm.doc.posting_time = frappe.datetime.now_time();
this.frm.doc.pos_profile = this.pos_profile_data['name'];
invoice_data[this.name] = this.frm.doc
this.si_docs.push(invoice_data)
invoice_data[this.frm.doc.offline_pos_name] = this.frm.doc;
this.si_docs.push(invoice_data);
this.update_localstorage();
this.set_primary_action();
}
@@ -1601,12 +1636,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.si_docs = this.get_doc_from_localstorage();
$.each(this.si_docs, function (index, data) {
for (var key in data) {
if (key == me.name) {
if (key == me.frm.doc.offline_pos_name) {
me.si_docs[index][key] = me.frm.doc;
me.update_localstorage();
}
}
})
});
},
update_localstorage: function () {
@@ -1628,6 +1663,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
set_interval_for_si_sync: function () {
var me = this;
setInterval(function () {
me.freeze_screen = false;
me.sync_sales_invoice()
}, 60000)
},
@@ -1641,9 +1677,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.freeze = this.customer_doc.display
}
freeze_screen = this.freeze_screen || false;
if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) {
this.freeze = true;
frappe.call({
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
freeze: freeze_screen,
args: {
doc_list: me.si_docs,
email_queue_list: me.email_queue_list,
@@ -1651,17 +1692,19 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
},
callback: function (r) {
if (r.message) {
me.freeze = false;
me.customers = r.message.synced_customers_list;
me.address = r.message.synced_address;
me.contacts = r.message.synced_contacts;
me.removed_items = r.message.invoice;
me.removed_email = r.message.email_queue
me.removed_customers = r.message.customers
me.removed_email = r.message.email_queue;
me.removed_customers = r.message.customers;
me.remove_doc_from_localstorage();
me.remove_email_queue_from_localstorage();
me.remove_customer_from_localstorage();
me.prepare_customer_mapper()
me.autocomplete_customers()
me.prepare_customer_mapper();
me.autocomplete_customers();
me.render_list_customers();
}
}
})

View File

@@ -1,16 +1,16 @@
QUnit.test("test:POS Profile", function(assert) {
assert.expect(1);
QUnit.test("test:Sales Invoice", function(assert) {
assert.expect(3);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make("POS Profile", [
{naming_series: "SINV"},
{company: "Test Company"},
{pos_profile_name: "_Test POS Profile"},
{country: "India"},
{currency: "INR"},
{write_off_account: "Write Off - TC"},
{write_off_cost_center: "Main - TC"},
{write_off_account: "Write Off - FT"},
{write_off_cost_center: "Main - FT"},
{payments: [
[
{"default": 1},
@@ -24,19 +24,10 @@ QUnit.test("test:POS Profile", function(assert) {
() => {
assert.equal(cur_frm.doc.payments[0].default, 1, "Default mode of payment tested");
},
() => done()
]);
});
QUnit.test("test:Sales Invoice", function(assert) {
assert.expect(2);
let done = assert.async();
frappe.run_serially([
() => frappe.timeout(1),
() => {
return frappe.tests.make("Sales Invoice", [
{customer: "Test Customer 2"},
{company: "Test Company"},
{is_pos: 1},
{posting_date: frappe.datetime.get_today()},
{due_date: frappe.datetime.get_today()},
@@ -44,7 +35,7 @@ QUnit.test("test:Sales Invoice", function(assert) {
[
{"item_code": "Test Product 1"},
{"qty": 5},
{"warehouse":'Stores - TC'}
{"warehouse":'Stores - FT'}
]]
}
]);

View File

@@ -68,16 +68,18 @@ def set_address_details(out, party, party_type, doctype=None, company=None):
billing_address_field = "customer_address" if party_type == "Lead" \
else party_type.lower() + "_address"
out[billing_address_field] = get_default_address(party_type, party.name)
out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
if doctype:
out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
# address display
out.address_display = get_address_display(out[billing_address_field])
# shipping address
if party_type in ["Customer", "Lead"]:
out.shipping_address_name = get_default_address(party_type, party.name, 'is_shipping_address')
out.shipping_address_name = get_party_shipping_address(party_type, party.name)
out.shipping_address = get_address_display(out["shipping_address_name"])
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
if doctype:
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
if doctype and doctype in ['Delivery Note', 'Sales Invoice']:
out.update(get_company_address(company))
@@ -320,11 +322,15 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup
from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details
args = {
party_type.lower(): party,
"customer_group": customer_group,
"supplier_type": supplier_type,
"company": company
}
if customer_group:
args['customer_group'] = customer_group
if supplier_type:
args['supplier_type'] = supplier_type
if billing_address or shipping_address:
args.update(get_party_details(party, party_type, {"billing_address": billing_address, \
"shipping_address": shipping_address }))
@@ -412,3 +418,32 @@ def get_dashboard_info(party_type, party):
info["total_unpaid"] = -1 * info["total_unpaid"]
return info
def get_party_shipping_address(doctype, name):
"""
Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true.
and/or `is_shipping_address = 1`.
It returns an empty string if there is no matching record.
:param doctype: Party Doctype
:param name: Party name
:return: String
"""
out = frappe.db.sql(
'SELECT dl.parent '
'from `tabDynamic Link` dl join `tabAddress` ta on dl.parent=ta.name '
'where '
'dl.link_doctype=%s '
'and dl.link_name=%s '
'and dl.parenttype="Address" '
'and '
'(ta.address_type="Shipping" or ta.is_shipping_address=1) '
'order by ta.is_shipping_address desc, ta.address_type desc limit 1',
(doctype, name)
)
if out:
return out[0][0]
else:
return ''

View File

@@ -0,0 +1,22 @@
{
"align_labels_right": 0,
"creation": "2017-08-08 12:33:04.773099",
"custom_format": 1,
"disabled": 0,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n<p><b>Tax Breakup:</b></p>\n<div style=\"font-size: 8px\">\n\t{{ doc.other_charges_calculation }}\n</div>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 0,
"line_breaks": 0,
"modified": "2017-09-14 15:54:19.467642",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GST POS Invoice",
"owner": "Administrator",
"print_format_builder": 0,
"print_format_type": "Server",
"show_section_headings": 0,
"standard": "Yes"
}

View File

@@ -1,5 +1,5 @@
{
"align_labels_left": 0,
"align_labels_right": 0,
"creation": "2016-05-05 17:16:18.564460",
"custom_format": 1,
"disabled": 0,
@@ -10,7 +10,7 @@
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{ __(\"POS No : \") }} {{ offline_pos_name }}<br>\n</p>\n<p>\n\t<b>{{ __(\"Customer\") }}:</b> {{ customer }}<br>\n</p>\n\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, null,precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p>{{ terms }}</p>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>",
"idx": 0,
"line_breaks": 0,
"modified": "2017-05-19 14:36:04.740728",
"modified": "2017-09-14 14:36:04.740728",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Point of Sale",

View File

@@ -10,15 +10,15 @@
<thead>
<tr>
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
<th style="width: 15%">{%= __("Date") %}</th>
<th style="width: 15%">{%= __("Ref") %}</th>
<th style="width: 40%">{%= __("Party") %}</th>
<th style="width: 15%">{%= __("Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
<th style="width: 15%">{%= __("Outstanding Amount") %}</th>
<th style="width: 14%">{%= __("Date") %}</th>
<th style="width: 16%">{%= __("Ref") %}</th>
<th style="width: 30%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 10%">{%= __("Invoiced Amount") %}</th>
<th style="width: 10%">{%= __("Paid Amount") %}</th>
<th style="width: 10%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
<th style="width: 10%">{%= __("Outstanding Amount") %}</th>
{% } else { %}
<th style="width: 40%">{%= __("Party") %}</th>
<th style="width: 40%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
<th style="width: 15%">{%= __("Total Invoiced Amount") %}</th>
<th style="width: 15%">{%= __("Total Paid Amount") %}</th>
<th style="width: 15%">{%= report.report_name === "Accounts Receivable Summary" ? __('Credit Note Amount') : __('Debit Note Amount') %}</th>
@@ -34,8 +34,12 @@
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Voucher Type")] %}
<br>{%= data[i][__("Voucher No")] %}</td>
<td>{%= data[i][__("Customer Name")] || data[i][__("Customer")] || data[i][__("Supplier Name")] || data[i][__("Supplier")] %}
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer Name")] || data[i][__("Customer")] || data[i][__("Supplier Name")] || data[i][__("Supplier")] %}<br>{%= __("Remarks") %}:
{% } %}
{%= data[i][__("Remarks")] %}
</td>
<td style="text-align: right">
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"]) %}</td>
<td style="text-align: right">
@@ -59,8 +63,13 @@
{% } else { %}
{% if(data[i][__("Customer")] || data[i][__("Supplier")]|| "&nbsp;") { %}
{% if((data[i][__("Customer")] || data[i][__("Supplier")]) != __("'Total'")) { %}
<td>{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
<td>
{% if(!(filters.customer || filters.supplier)) { %}
{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
<br>{%= __("Remarks") %}:
{% } %}
{%= data[i][__("Remarks")] %}
</td>
{% } else { %}
<td><b>{%= __("Total") %}</b></td>
{% } %}

View File

@@ -44,7 +44,7 @@ class ReceivablePayableReport(object):
})
columns += [_("Age (Days)") + ":Int:80"]
self.ageing_col_idx_start = len(columns)
if not "range1" in self.filters:
@@ -53,7 +53,7 @@ class ReceivablePayableReport(object):
self.filters["range2"] = "60"
if not "range3" in self.filters:
self.filters["range3"] = "90"
for label in ("0-{range1}".format(range1=self.filters["range1"]),
"{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
@@ -74,14 +74,14 @@ class ReceivablePayableReport(object):
})
if args.get("party_type") == "Customer":
columns += [
_("Territory") + ":Link/Territory:80",
_("Territory") + ":Link/Territory:80",
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
columns.append(_("Remarks") + "::200")
return columns
def get_data(self, party_naming_by, args):
@@ -97,13 +97,13 @@ class ReceivablePayableReport(object):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
company_currency = frappe.db.get_value("Company", self.filters.get("company"), "default_currency")
return_entries = self.get_return_entries(args.get("party_type"))
data = []
for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")):
if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle,
outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle,
self.filters.report_date, dr_or_cr, return_entries, currency_precision)
if abs(outstanding_amount) > 0.1/10**currency_precision:
row = [gle.posting_date, gle.party]
@@ -179,15 +179,15 @@ class ReceivablePayableReport(object):
# entries adjusted with future vouchers
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
)
def get_return_entries(self, party_type):
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries, currency_precision):
payment_amount, credit_note_amount = 0.0, 0.0
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr))
@@ -195,11 +195,11 @@ class ReceivablePayableReport(object):
payment_amount += amount
else:
credit_note_amount += amount
outstanding_amount = flt((flt(gle.get(dr_or_cr)) - flt(gle.get(reverse_dr_or_cr)) \
- payment_amount - credit_note_amount), currency_precision)
credit_note_amount = flt(credit_note_amount, currency_precision)
return outstanding_amount, credit_note_amount
def get_party_name(self, party_type, party_name):
@@ -207,7 +207,7 @@ class ReceivablePayableReport(object):
def get_territory(self, party_name):
return self.get_party_map("Customer").get(party_name, {}).get("territory") or ""
def get_customer_group(self, party_name):
return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or ""
@@ -220,7 +220,7 @@ class ReceivablePayableReport(object):
select_fields = "name, customer_name, territory, customer_group"
elif party_type == "Supplier":
select_fields = "name, supplier_name, supplier_type"
self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`"
.format(select_fields, party_type), as_dict=True)))
@@ -250,8 +250,8 @@ class ReceivablePayableReport(object):
else:
select_fields = "sum(debit) as debit, sum(credit) as credit"
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party,
voucher_type, voucher_no, against_voucher_type, against_voucher,
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party,
voucher_type, voucher_no, against_voucher_type, against_voucher,
account_currency, remarks, {0}
from `tabGL Entry`
where docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
@@ -277,13 +277,13 @@ class ReceivablePayableReport(object):
if party_type_field=="customer":
if self.filters.get("customer_group"):
lft, rgt = frappe.db.get_value("Customer Group",
lft, rgt = frappe.db.get_value("Customer Group",
self.filters.get("customer_group"), ["lft", "rgt"])
conditions.append("""party in (select name from tabCustomer
where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
conditions.append("""party in (select name from tabCustomer
where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
and name=tabCustomer.customer_group))""".format(lft, rgt))
if self.filters.get("credit_days_based_on"):
conditions.append("party in (select name from tabCustomer where credit_days_based_on=%s)")
values.append(self.filters.get("credit_days_based_on"))
@@ -303,22 +303,22 @@ class ReceivablePayableReport(object):
return self.gl_entries_map.get(party, {})\
.get(against_voucher_type, {})\
.get(against_voucher, [])
def get_chart_data(self, columns, data):
ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
rows = []
for d in data:
rows.append(d[self.ageing_col_idx_start : self.ageing_col_idx_start+4])
if rows:
rows.insert(0, [[d.get("label")] for d in ageing_columns])
return {
"data": {
'rows': rows
'labels': rows
},
"chart_type": 'pie'
"type": 'percentage'
}
def execute(filters=None):

View File

@@ -8,18 +8,18 @@ from frappe.utils import flt, cint
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, company=filters.company)
asset = get_data(filters.company, "Asset", "Debit", period_list,
asset = get_data(filters.company, "Asset", "Debit", period_list,
only_current_fiscal_year=False, filters=filters,
accumulated_values=filters.accumulated_values)
liability = get_data(filters.company, "Liability", "Credit", period_list,
liability = get_data(filters.company, "Liability", "Credit", period_list,
only_current_fiscal_year=False, filters=filters,
accumulated_values=filters.accumulated_values)
equity = get_data(filters.company, "Equity", "Credit", period_list,
equity = get_data(filters.company, "Equity", "Credit", period_list,
only_current_fiscal_year=False, filters=filters,
accumulated_values=filters.accumulated_values)
@@ -43,17 +43,17 @@ def execute(filters=None):
unclosed[period.key] = opening_balance
if provisional_profit_loss:
provisional_profit_loss[period.key] = provisional_profit_loss[period.key] - opening_balance
unclosed["total"]=opening_balance
data.append(unclosed)
if provisional_profit_loss:
data.append(provisional_profit_loss)
if total_credit:
data.append(total_credit)
data.append(total_credit)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, company=filters.company)
chart = get_chart_data(filters, columns, asset, liability, equity)
return columns, data, message, chart
@@ -87,7 +87,7 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company):
total += flt(provisional_profit_loss[period.key])
provisional_profit_loss["total"] = total
total_row_total += flt(total_row[period.key])
total_row["total"] = total_row_total
@@ -98,7 +98,7 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company):
"warn_if_negative": True,
"currency": currency
})
return provisional_profit_loss, total_row
def check_opening_balance(asset, liability, equity):
@@ -111,17 +111,17 @@ def check_opening_balance(asset, liability, equity):
opening_balance -= flt(liability[0].get("opening_balance", 0), float_precision)
if equity:
opening_balance -= flt(equity[0].get("opening_balance", 0), float_precision)
opening_balance = flt(opening_balance, float_precision)
if opening_balance:
return _("Previous Financial Year is not closed"),opening_balance
return None,None
def get_chart_data(filters, columns, asset, liability, equity):
x_intervals = ['x'] + [d.get("label") for d in columns[2:]]
labels = [d.get("label") for d in columns[2:]]
asset_data, liability_data, equity_data = [], [], []
for p in columns[2:]:
if asset:
asset_data.append(asset[-2].get(p.get("fieldname")))
@@ -129,23 +129,25 @@ def get_chart_data(filters, columns, asset, liability, equity):
liability_data.append(liability[-2].get(p.get("fieldname")))
if equity:
equity_data.append(equity[-2].get(p.get("fieldname")))
columns = [x_intervals]
datasets = []
if asset_data:
columns.append(["Assets"] + asset_data)
datasets.append({'title':'Assets', 'values': asset_data})
if liability_data:
columns.append(["Liabilities"] + liability_data)
datasets.append({'title':'Liabilities', 'values': liability_data})
if equity_data:
columns.append(["Equity"] + equity_data)
datasets.append({'title':'Equity', 'values': equity_data})
chart = {
"data": {
'x': 'x',
'columns': columns
'labels': labels,
'datasets': datasets
}
}
if not filters.accumulated_values:
chart["chart_type"] = "bar"
chart["type"] = "bar"
else:
chart["type"] = "line"
return chart

View File

@@ -99,7 +99,8 @@ def get_actual_details(name, filters):
where
b.name = ba.parent
and b.docstatus = 1
and ba.account=gl.account
and ba.account=gl.account
and b.{budget_against} = gl.{budget_against}
and gl.fiscal_year=%s
and b.{budget_against}=%s
and exists(select name from `tab{tab}` where name=gl.{budget_against} and {cond})

View File

@@ -142,10 +142,16 @@ def get_data(company, root_type, balance_must_be, period_list, filters=None,
return out
def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy):
for entries in gl_entries_by_account.values():
for entry in entries:
d = accounts_by_name.get(entry.account)
if not d:
frappe.msgprint(
_("Could not retrieve information for {0}.".format(entry.account)), title="Error",
raise_exception=1
)
for period in period_list:
# check if posting date is within the period

View File

@@ -17,7 +17,6 @@ def execute(filters=None):
gross_profit_data = GrossProfitGenerator(filters)
data = []
source = gross_profit_data.grouped_data if filters.get("group_by") != "Invoice" else gross_profit_data.data
group_wise_columns = frappe._dict({
"invoice": ["parent", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "brand", "description", \
@@ -45,7 +44,7 @@ def execute(filters=None):
columns = get_columns(group_wise_columns, filters)
for src in source:
for src in gross_profit_data.grouped_data:
row = []
for col in group_wise_columns.get(scrub(filters.group_by)):
row.append(src.get(col))
@@ -103,10 +102,13 @@ class GrossProfitGenerator(object):
self.load_stock_ledger_entries()
self.load_product_bundle()
self.load_non_stock_items()
self.get_returned_invoice_items()
self.process()
def process(self):
self.grouped = {}
self.grouped_data = []
for row in self.si_list:
if self.skip_row(row, self.product_bundles):
continue
@@ -143,40 +145,67 @@ class GrossProfitGenerator(object):
row.gross_profit_percent = 0.0
# add to grouped
if self.filters.group_by != "Invoice":
self.grouped.setdefault(row.get(scrub(self.filters.group_by)), []).append(row)
self.data.append(row)
self.grouped.setdefault(row.get(scrub(self.filters.group_by)), []).append(row)
if self.grouped:
self.get_average_rate_based_on_group_by()
else:
self.grouped_data = []
def get_average_rate_based_on_group_by(self):
# sum buying / selling totals for group
self.grouped_data = []
for key in self.grouped.keys():
for i, row in enumerate(self.grouped[key]):
if i==0:
new_row = row
else:
new_row.qty += row.qty
new_row.buying_amount += row.buying_amount
new_row.base_amount += row.base_amount
if self.filters.get("group_by") != "Invoice":
for i, row in enumerate(self.grouped[key]):
if i==0:
new_row = row
else:
new_row.qty += row.qty
new_row.buying_amount += row.buying_amount
new_row.base_amount += row.base_amount
new_row = self.set_average_rate(new_row)
self.grouped_data.append(new_row)
else:
for i, row in enumerate(self.grouped[key]):
if row.parent in self.returned_invoices \
and row.item_code in self.returned_invoices[row.parent]:
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
for returned_item_row in returned_item_rows:
row.qty += returned_item_row.qty
row.base_amount += returned_item_row.base_amount
row.buying_amount = row.qty * row.buying_rate
if row.qty:
row = self.set_average_rate(row)
self.grouped_data.append(row)
new_row.gross_profit = new_row.base_amount - new_row.buying_amount
new_row.gross_profit_percent = ((new_row.gross_profit / new_row.base_amount) * 100.0) \
if new_row.base_amount else 0
new_row.buying_rate = (new_row.buying_amount / new_row.qty) \
if new_row.qty else 0
new_row.base_rate = (new_row.base_amount / new_row.qty) \
if new_row.qty else 0
def set_average_rate(self, new_row):
new_row.gross_profit = new_row.base_amount - new_row.buying_amount
new_row.gross_profit_percent = ((new_row.gross_profit / new_row.base_amount) * 100.0) \
if new_row.base_amount else 0
new_row.buying_rate = (new_row.buying_amount / new_row.qty) if new_row.qty else 0
new_row.base_rate = (new_row.base_amount / new_row.qty) if new_row.qty else 0
return new_row
self.grouped_data.append(new_row)
def get_returned_invoice_items(self):
returned_invoices = frappe.db.sql("""
select
si.name, si_item.item_code, si_item.qty, si_item.base_amount, si.return_against
from
`tabSales Invoice` si, `tabSales Invoice Item` si_item
where
si.name = si_item.parent
and si.docstatus = 1
and si.is_return = 1
""", as_dict=1)
self.returned_invoices = frappe._dict()
for inv in returned_invoices:
self.returned_invoices.setdefault(inv.return_against, frappe._dict())\
.setdefault(inv.item_code, []).append(inv)
def skip_row(self, row, product_bundles):
if self.filters.get("group_by") != "Invoice" and not row.get(scrub(self.filters.get("group_by"))):
if self.filters.get("group_by") != "Invoice":
if not row.get(scrub(self.filters.get("group_by"))):
return True
elif row.get("is_return") == 1:
return True
def get_buying_amount_from_product_bundle(self, row, product_bundle):
@@ -268,20 +297,26 @@ class GrossProfitGenerator(object):
sales_person_cols = ""
sales_team_table = ""
self.si_list = frappe.db.sql("""select `tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.posting_time, `tabSales Invoice`.project, `tabSales Invoice`.update_stock,
`tabSales Invoice`.customer, `tabSales Invoice`.customer_group, `tabSales Invoice`.territory,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.item_name, `tabSales Invoice Item`.description,
`tabSales Invoice Item`.warehouse, `tabSales Invoice Item`.item_group, `tabSales Invoice Item`.brand,
`tabSales Invoice Item`.dn_detail, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice Item`.name as "item_row"
self.si_list = frappe.db.sql("""
select
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.posting_time,
`tabSales Invoice`.project, `tabSales Invoice`.update_stock,
`tabSales Invoice`.customer, `tabSales Invoice`.customer_group,
`tabSales Invoice`.territory, `tabSales Invoice Item`.item_code,
`tabSales Invoice Item`.item_name, `tabSales Invoice Item`.description,
`tabSales Invoice Item`.warehouse, `tabSales Invoice Item`.item_group,
`tabSales Invoice Item`.brand, `tabSales Invoice Item`.dn_detail,
`tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
`tabSales Invoice Item`.name as "item_row", `tabSales Invoice`.is_return
{sales_person_cols}
from
`tabSales Invoice`
inner join `tabSales Invoice Item` on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
`tabSales Invoice` inner join `tabSales Invoice Item`
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
{sales_team_table}
where
`tabSales Invoice`.docstatus = 1 {conditions} {match_cond}
`tabSales Invoice`.docstatus=1 {conditions} {match_cond}
order by
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
.format(conditions=conditions, sales_person_cols=sales_person_cols,

View File

@@ -49,7 +49,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row += [
d.credit_to, d.mode_of_payment, d.project, d.company, d.purchase_order,
purchase_receipt, expense_account, d.qty, d.stock_uom, d.base_net_rate, d.base_net_amount
purchase_receipt, expense_account, d.stock_qty, d.stock_uom, d.base_net_rate, d.base_net_amount
]
total_tax = 0
@@ -81,7 +81,7 @@ def get_columns(additional_table_columns):
_("Mode of Payment") + ":Link/Mode of Payment:80", _("Project") + ":Link/Project:80",
_("Company") + ":Link/Company:100", _("Purchase Order") + ":Link/Purchase Order:100",
_("Purchase Receipt") + ":Link/Purchase Receipt:100", _("Expense Account") + ":Link/Account:140",
_("Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Rate") + ":Currency/currency:120", _("Amount") + ":Currency/currency:120"
]
@@ -91,10 +91,10 @@ def get_conditions(filters):
conditions = ""
for opts in (("company", " and company=%(company)s"),
("supplier", " and pi.supplier = %(supplier)s"),
("item_code", " and pi_item.item_code = %(item_code)s"),
("from_date", " and pi.posting_date>=%(from_date)s"),
("to_date", " and pi.posting_date<=%(to_date)s"),
("supplier", " and `tabPurchase Invoice`.supplier = %(supplier)s"),
("item_code", " and `tabPurchase Invoice Item`.item_code = %(item_code)s"),
("from_date", " and `tabPurchase Invoice`.posting_date>=%(from_date)s"),
("to_date", " and `tabPurchase Invoice`.posting_date<=%(to_date)s"),
("mode_of_payment", " and ifnull(mode_of_payment, '') = %(mode_of_payment)s")):
if filters.get(opts[0]):
conditions += opts[1]
@@ -104,20 +104,29 @@ def get_conditions(filters):
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Purchase Invoice")
if match_conditions:
match_conditions = " and {0} ".format(match_conditions)
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
return frappe.db.sql("""
select
pi_item.name, pi_item.parent, pi.posting_date, pi.credit_to, pi.company,
pi.supplier, pi.remarks, pi.base_net_total, pi_item.item_code, pi_item.item_name,
pi_item.item_group, pi_item.project, pi_item.purchase_order, pi_item.purchase_receipt,
pi_item.po_detail, pi_item.expense_account, pi_item.qty, pi_item.stock_uom,
pi_item.base_net_rate, pi_item.base_net_amount,
pi.supplier_name, pi.mode_of_payment {0}
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
where pi.name = pi_item.parent and pi.docstatus = 1 %s %s
order by pi.posting_date desc, pi_item.item_code desc
`tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`,
`tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company,
`tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, `tabPurchase Invoice Item`.`item_code`,
`tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`,
`tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`,
`tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`,
`tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`,
`tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_rate`,
`tabPurchase Invoice Item`.`base_net_amount`,
`tabPurchase Invoice`.supplier_name, `tabPurchase Invoice`.mode_of_payment {0}
from `tabPurchase Invoice`, `tabPurchase Invoice Item`
where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and
`tabPurchase Invoice`.docstatus = 1 %s %s
order by `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc
""".format(additional_query_columns) % (conditions, match_conditions), filters, as_dict=1)
def get_aii_accounts():

View File

@@ -49,7 +49,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
row += [
d.customer_group, d.debit_to, ", ".join(mode_of_payments.get(d.parent, [])),
d.territory, d.project, d.company, d.sales_order,
delivery_note, d.income_account, d.cost_center, d.qty, d.stock_uom,
delivery_note, d.income_account, d.cost_center, d.stock_qty, d.stock_uom,
d.base_net_rate, d.base_net_amount
]
@@ -82,7 +82,7 @@ def get_columns(additional_table_columns):
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
_("Income Account") + ":Link/Account:140", _("Cost Center") + ":Link/Cost Center:140",
_("Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Stock Qty") + ":Float:120", _("Stock UOM") + "::100",
_("Rate") + ":Currency/currency:120",
_("Amount") + ":Currency/currency:120"
]
@@ -93,37 +93,49 @@ def get_conditions(filters):
conditions = ""
for opts in (("company", " and company=%(company)s"),
("customer", " and si.customer = %(customer)s"),
("item_code", " and si_item.item_code = %(item_code)s"),
("from_date", " and si.posting_date>=%(from_date)s"),
("to_date", " and si.posting_date<=%(to_date)s")):
("customer", " and `tabSales Invoice`.customer = %(customer)s"),
("item_code", " and `tabSales Invoice Item`.item_code = %(item_code)s"),
("from_date", " and `tabSales Invoice`.posting_date>=%(from_date)s"),
("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s")):
if filters.get(opts[0]):
conditions += opts[1]
if filters.get("mode_of_payment"):
conditions += """ and exists(select name from `tabSales Invoice Payment`
where parent=si.name
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
where parent=si.name
and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)"""
return conditions
def get_items(filters, additional_query_columns):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Sales Invoice")
if match_conditions:
match_conditions = " and {0} ".format(match_conditions)
if additional_query_columns:
additional_query_columns = ', ' + ', '.join(additional_query_columns)
conditions = get_conditions(filters)
return frappe.db.sql("""
select
si_item.name, si_item.parent, si.posting_date, si.debit_to, si.project,
si.customer, si.remarks, si.territory, si.company, si.base_net_total,
si_item.item_code, si_item.item_name, si_item.item_group, si_item.sales_order,
si_item.delivery_note, si_item.income_account, si_item.cost_center,
si_item.qty, si_item.stock_uom, si_item.base_net_rate, si_item.base_net_amount,
si.customer_name, si.customer_group, si_item.so_detail, si.update_stock {0}
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 %s
order by si.posting_date desc, si_item.item_code desc
""".format(additional_query_columns or '') % conditions, filters, as_dict=1)
`tabSales Invoice Item`.name, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to,
`tabSales Invoice`.project, `tabSales Invoice`.customer, `tabSales Invoice`.remarks,
`tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total,
`tabSales Invoice Item`.item_code, `tabSales Invoice Item`.item_name,
`tabSales Invoice Item`.item_group, `tabSales Invoice Item`.sales_order,
`tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account,
`tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty,
`tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate,
`tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name,
`tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
`tabSales Invoice`.update_stock {0}
from `tabSales Invoice`, `tabSales Invoice Item`
where `tabSales Invoice`.name = `tabSales Invoice Item`.parent
and `tabSales Invoice`.docstatus = 1 %s %s
order by `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_code desc
""".format(additional_query_columns or '') % (conditions, match_conditions), filters, as_dict=1)
def get_delivery_notes_against_sales_order(item_list):
so_dn_map = frappe._dict()

View File

@@ -8,15 +8,15 @@ from frappe.utils import flt
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.accumulated_values, filters.company)
income = get_data(filters.company, "Income", "Credit", period_list, filters = filters,
accumulated_values=filters.accumulated_values,
accumulated_values=filters.accumulated_values,
ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
expense = get_data(filters.company, "Expense", "Debit", period_list, filters=filters,
accumulated_values=filters.accumulated_values,
accumulated_values=filters.accumulated_values,
ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
@@ -61,7 +61,7 @@ def get_net_profit_loss(income, expense, period_list, company):
def get_chart_data(filters, columns, income, expense, net_profit_loss):
x_intervals = ['x'] + [d.get("label") for d in columns[2:]]
labels = [d.get("label") for d in columns[2:]]
income_data, expense_data, net_profit = [], [], []
@@ -73,27 +73,24 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss):
if net_profit_loss:
net_profit.append(net_profit_loss.get(p.get("fieldname")))
columns = [x_intervals]
datasets = []
if income_data:
columns.append(["Income"] + income_data)
datasets.append({'title': 'Income', 'values': income_data})
if expense_data:
columns.append(["Expense"] + expense_data)
datasets.append({'title': 'Expense', 'values': expense_data})
if net_profit:
columns.append(["Net Profit/Loss"] + net_profit)
datasets.append({'title': 'Net Profit/Loss', 'values': net_profit})
chart = {
"data": {
'x': 'x',
'columns': columns,
'colors': {
'Income': '#5E64FF',
'Expense': '#b8c2cc',
'Net Profit/Loss': '#ff5858'
}
'labels': labels,
'datasets': datasets
}
}
if not filters.accumulated_values:
chart["chart_type"] = "bar"
chart["type"] = "bar"
else:
chart["type"] = "line"
return chart

View File

View File

@@ -0,0 +1,84 @@
import unittest
from erpnext.accounts.party import get_party_shipping_address
from frappe.test_runner import make_test_objects
class TestUtils(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(TestUtils, cls).setUpClass()
make_test_objects('Address', ADDRESS_RECORDS)
def test_get_party_shipping_address(self):
address = get_party_shipping_address('Customer', '_Test Customer 1')
self.assertEqual(address, '_Test Billing Address 2 Title-Billing')
def test_get_party_shipping_address2(self):
address = get_party_shipping_address('Customer', '_Test Customer 2')
self.assertEqual(address, '_Test Shipping Address 2 Title-Shipping')
ADDRESS_RECORDS = [
{
"doctype": "Address",
"address_type": "Billing",
"address_line1": "Address line 1",
"address_title": "_Test Billing Address Title",
"city": "Lagos",
"country": "Nigeria",
"links": [
{
"link_doctype": "Customer",
"link_name": "_Test Customer 2",
"doctype": "Dynamic Link"
}
]
},
{
"doctype": "Address",
"address_type": "Shipping",
"address_line1": "Address line 2",
"address_title": "_Test Shipping Address 1 Title",
"city": "Lagos",
"country": "Nigeria",
"links": [
{
"link_doctype": "Customer",
"link_name": "_Test Customer 2",
"doctype": "Dynamic Link"
}
]
},
{
"doctype": "Address",
"address_type": "Shipping",
"address_line1": "Address line 3",
"address_title": "_Test Shipping Address 2 Title",
"city": "Lagos",
"country": "Nigeria",
"is_shipping_address": "1",
"links": [
{
"link_doctype": "Customer",
"link_name": "_Test Customer 2",
"doctype": "Dynamic Link"
}
]
},
{
"doctype": "Address",
"address_type": "Billing",
"address_line1": "Address line 4",
"address_title": "_Test Billing Address 2 Title",
"city": "Lagos",
"country": "Nigeria",
"is_shipping_address": "1",
"links": [
{
"link_doctype": "Customer",
"link_name": "_Test Customer 1",
"doctype": "Dynamic Link"
}
]
}
]

View File

@@ -13,14 +13,39 @@ frappe.ui.form.on("Purchase Order", {
'Stock Entry': 'Material to Supplier'
}
},
onload: function(frm) {
set_schedule_date(frm);
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
frm.set_indicator_formatter('item_code',
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
},
});
frappe.ui.form.on("Purchase Order Item", {
item_code: function(frm) {
frappe.call({
method: "get_last_purchase_rate",
doc: frm.doc,
callback: function(r, rt) {
frm.trigger('calculate_taxes_and_totals');
}
})
},
schedule_date: function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
if (row.schedule_date) {
if(!frm.doc.schedule_date) {
erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date");
} else {
set_schedule_date(frm);
}
}
}
});
@@ -86,8 +111,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __("Make"));
}
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
if(!doc.subscription) {
cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __("Make"))
}
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
}
},
@@ -102,12 +132,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
},
validate: function() {
// set default schedule date as today if missing.
(this.frm.doc.items || []).forEach(function(d) {
if(!d.schedule_date) {
d.schedule_date = frappe.datetime.nowdate();
}
})
set_schedule_date(this.frm);
},
make_stock_entry: function() {
@@ -196,7 +221,12 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
if(doc.schedule_date) {
row.schedule_date = doc.schedule_date;
refresh_field("schedule_date", cdn, "items");
} else {
this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]);
}
},
unclose_purchase_order: function(){
@@ -220,8 +250,15 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
cur_frm.cscript.calculate_taxes_and_totals();
}
})
}
},
items_on_form_rendered: function() {
set_schedule_date(this.frm);
},
schedule_date: function() {
set_schedule_date(this.frm);
}
});
// for backward compatibility: combine new and previous states
@@ -263,8 +300,10 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
}
}
cur_frm.cscript.schedule_date = function(doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date");
function set_schedule_date(frm) {
if(frm.doc.schedule_date){
erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date");
}
}
frappe.provide("erpnext.buying");

View File

@@ -291,9 +291,40 @@
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
},
{
"allow_bulk_edit": 0,
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "schedule_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": "Reqd By 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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1206,37 +1237,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
"fieldname": "get_last_purchase_rate",
"fieldtype": "Button",
"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": "Get last purchase rate",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2102,6 +2102,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment (Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2227,6 +2258,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2860,11 +2922,9 @@
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "is_recurring",
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2 && !doc.__islocal",
"fieldname": "recurring_order",
"fieldname": "subscription_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -2873,40 +2933,11 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Recurring Order",
"length": 0,
"no_copy": 0,
"options": "fa fa-time",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break",
"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,
"label": "Settings",
"label": "Subscription Section",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -2923,320 +2954,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus<2",
"description": "",
"fieldname": "is_recurring",
"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": "Is Recurring",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"description": "",
"fieldname": "recurring_id",
"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": "Reference Document",
"length": 0,
"no_copy": 1,
"options": "Purchase Order",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "recurring_type",
"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": "Frequency",
"length": 0,
"no_copy": 1,
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "repeat_on_day_of_month",
"fieldtype": "Int",
"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": "Repeat on Day of Month",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "end_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": "End Date",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"fieldname": "submit_on_creation",
"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": "Submit on creation",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name",
"description": "",
"fieldname": "notify_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 by email",
"length": 0,
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name",
"description": "",
"fieldname": "notification_email_address",
"fieldtype": "Code",
"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": "Notification Email Address",
"length": 0,
"no_copy": 1,
"options": "Email",
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name",
"fieldname": "recurring_print_format",
"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": "Recurring Print Format",
"length": 0,
"no_copy": 0,
"options": "Print Format",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break83",
"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,
"label": "This Document",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"depends_on": "",
"description": "",
"fieldname": "from_date",
"fieldtype": "Date",
@@ -3267,7 +2985,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"depends_on": "",
"description": "",
"fieldname": "to_date",
"fieldtype": "Date",
@@ -3298,10 +3016,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_recurring",
"description": "",
"fieldname": "next_date",
"fieldtype": "Date",
"fieldname": "column_break_97",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -3309,11 +3025,11 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Next Date",
"length": 0,
"no_copy": 1,
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -3322,6 +3038,37 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription",
"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": "Subscription",
"length": 0,
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
}
],
"has_web_view": 0,
@@ -3335,7 +3082,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-19 14:03:51.838328",
"modified": "2017-10-24 12:52:11.272306",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -20,8 +20,8 @@ form_grid_templates = {
}
class PurchaseOrder(BuyingController):
def __init__(self, arg1, arg2=None):
super(PurchaseOrder, self).__init__(arg1, arg2)
def __init__(self, *args, **kwargs):
super(PurchaseOrder, self).__init__(*args, **kwargs)
self.status_updater = [{
'source_dt': 'Purchase Order Item',
'target_dt': 'Material Request Item',
@@ -41,6 +41,7 @@ class PurchaseOrder(BuyingController):
self.set_status()
self.validate_supplier()
self.validate_schedule_date()
validate_for_items(self)
self.check_for_closed_status()
@@ -116,14 +117,13 @@ class PurchaseOrder(BuyingController):
d.discount_percentage = last_purchase_details['discount_percentage']
d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0)
d.price_list_rate = d.base_price_list_rate / conversion_rate
d.rate = d.base_rate / conversion_rate
d.last_purchase_rate = d.base_rate / conversion_rate
else:
msgprint(_("Last purchase rate not found"))
item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate")
if item_last_purchase_rate:
d.base_price_list_rate = d.base_rate = d.price_list_rate \
= d.rate = item_last_purchase_rate
= d.last_purchase_rate = item_last_purchase_rate
# Check for Closed status
def check_for_closed_status(self):
@@ -295,6 +295,7 @@ def make_purchase_receipt(source_name, target_doc=None):
"field_map": {
"name": "purchase_order_item",
"parent": "purchase_order",
"bom": "bom"
},
"postprocess": update_item,
"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty) and doc.delivered_by_supplier!=1

View File

@@ -5,7 +5,8 @@ def get_data():
'fieldname': 'purchase_order',
'non_standard_fieldnames': {
'Journal Entry': 'reference_name',
'Payment Entry': 'reference_name'
'Payment Entry': 'reference_name',
'Subscription': 'reference_document'
},
'internal_links': {
'Material Request': ['items', 'material_request'],
@@ -23,11 +24,11 @@ def get_data():
},
{
'label': _('Reference'),
'items': ['Material Request', 'Supplier Quotation', 'Project']
'items': ['Material Request', 'Supplier Quotation', 'Project', 'Subscription']
},
{
'label': _('Sub-contracting'),
'items': ['Stock Entry']
}
},
]
}

View File

@@ -118,6 +118,7 @@ class TestPurchaseOrder(unittest.TestCase):
"company": "_Test Company",
"supplier" : "_Test Supplier",
"is_subcontracted" : "No",
"schedule_date": add_days(nowdate(), 1),
"currency" : frappe.db.get_value("Company", "_Test Company", "default_currency"),
"conversion_factor" : 1,
"items" : get_same_items(),
@@ -149,6 +150,7 @@ def create_purchase_order(**args):
if args.transaction_date:
po.transaction_date = args.transaction_date
po.schedule_date = add_days(nowdate(), 1)
po.company = args.company or "_Test Company"
po.supplier = args.customer or "_Test Supplier"
po.is_subcontracted = args.is_subcontracted or "No"

View File

@@ -30,7 +30,8 @@
],
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
"transaction_date": "2013-02-12",
"schedule_date": "2013-02-13"
},
{
"advance_paid": 0.0,
@@ -63,6 +64,7 @@
],
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
"transaction_date": "2013-02-12",
"schedule_date": "2013-02-13"
}
]

View File

@@ -1,7 +1,7 @@
QUnit.module('Buying');
QUnit.test("test: purchase order", function(assert) {
assert.expect(11);
assert.expect(16);
let done = assert.async();
frappe.run_serially([
@@ -13,12 +13,21 @@ QUnit.test("test: purchase order", function(assert) {
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 2)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 5},
{"uom": 'Unit'},
{"rate": 100},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 2},
{"uom": 'Unit'},
{"rate": 100},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]},
@@ -30,14 +39,20 @@ QUnit.test("test: purchase order", function(assert) {
() => {
// Get supplier details
assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Supplier name correct");
assert.ok($('div.control-value.like-disabled-input.for-description').text().includes('Contact 3'), "Contact display correct");
assert.ok(cur_frm.doc.schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 1), "Schedule Date correct");
assert.ok(cur_frm.doc.contact_email == 'test@supplier.com', "Contact email correct");
// Get item details
assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item name correct");
assert.ok(cur_frm.doc.items[0].description == 'Test Product 4', "Description correct");
assert.ok(cur_frm.doc.items[0].qty == 5, "Quantity correct");
assert.ok(cur_frm.doc.items[0].schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 2), "Schedule Date correct");
assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item name correct");
assert.ok(cur_frm.doc.items[1].description == 'Test Product 1', "Description correct");
assert.ok(cur_frm.doc.items[1].qty == 2, "Quantity correct");
assert.ok(cur_frm.doc.items[1].schedule_date == cur_frm.doc.schedule_date, "Schedule Date correct");
// Calculate total
assert.ok(cur_frm.doc.total == 500, "Total correct");
assert.ok(cur_frm.doc.total == 700, "Total correct");
// Get terms
assert.ok(cur_frm.doc.terms == 'This is a term.', "Terms correct");
},
@@ -54,7 +69,7 @@ QUnit.test("test: purchase order", function(assert) {
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(0.3),
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully");

View File

@@ -0,0 +1,99 @@
QUnit.module('Buying');
QUnit.test("test: purchase order with last purchase rate", function(assert) {
assert.expect(5);
let done = assert.async();
frappe.run_serially([
() => {
return frappe.tests.make('Purchase Order', [
{supplier: 'Test Supplier'},
{is_subcontracted: 'No'},
{currency: 'INR'},
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 800},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 400},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]}
]);
},
() => {
// Get item details
assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item 1 name correct");
assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item 2 name correct");
},
() => frappe.timeout(1),
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
() => {
return frappe.tests.make('Purchase Order', [
{supplier: 'Test Supplier'},
{is_subcontracted: 'No'},
{currency: 'INR'},
{items: [
[
{"item_code": 'Test Product 4'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 600},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
],
[
{"item_code": 'Test Product 1'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)},
{"qty": 1},
{"rate": 200},
{"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))}
]
]}
]);
},
() => frappe.timeout(2),
// Get the last purchase rate of items
() => {
assert.ok(cur_frm.doc.items[0].last_purchase_rate == 800, "Last purchase rate of item 1 correct");
},
() => {
assert.ok(cur_frm.doc.items[1].last_purchase_rate == 400, "Last purchase rate of item 2 correct");
},
() => frappe.tests.click_button('Submit'),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => frappe.tests.click_button('Close'),
() => frappe.timeout(1),
() => {
assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully");
},
() => done()
]);
});

View File

@@ -11,6 +11,7 @@ QUnit.test("test: purchase order with taxes and charges", function(assert) {
{is_subcontracted: 'No'},
{buying_price_list: 'Test-Buying-USD'},
{currency: 'USD'},
{"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)},
{items: [
[
{"item_code": 'Test Product 4'},

View File

@@ -140,7 +140,7 @@
"allow_on_submit": 1,
"bold": 1,
"collapsible": 0,
"columns": 0,
"columns": 2,
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
@@ -148,7 +148,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Reqd By Date",
"length": 0,
@@ -382,7 +382,7 @@
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 2,
"columns": 1,
"fieldname": "qty",
"fieldtype": "Float",
"hidden": 0,
@@ -655,6 +655,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "last_purchase_rate",
"fieldtype": "Currency",
"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": "Last Purchase Rate",
"length": 0,
"no_copy": 0,
"options": "currency",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -718,7 +749,7 @@
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 3,
"columns": 2,
"fieldname": "rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -1714,7 +1745,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-08-02 22:15:47.411235",
"modified": "2017-10-05 19:47:12.433095",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@@ -12,11 +12,11 @@ frappe.ui.form.on("Request for Quotation",{
'Supplier Quotation': 'Supplier Quotation'
}
frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn){
var d =locals[cdt][cdn];
frm.fields_dict["suppliers"].grid.get_field("contact").get_query = function(doc, cdt, cdn) {
let d = locals[cdt][cdn];
return {
query: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_supplier_contacts",
filters: {'supplier': doc.supplier}
filters: {'supplier': d.supplier}
}
}
},
@@ -254,6 +254,21 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
}
})
}, __("Get items from"));
// Get items from Opportunity
this.frm.add_custom_button(__('Opportunity'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.crm.doctype.opportunity.opportunity.make_request_for_quotation",
source_doctype: "Opportunity",
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
enquiry_type: "Sales"
}
})
}, __("Get items from"));
// Get items from open Material Requests based on supplier
this.frm.add_custom_button(__('Possible Supplier'), function() {
// Create a dialog window for the user to pick their supplier

View File

@@ -816,7 +816,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-21 14:06:46.309322",
"modified": "2017-10-17 17:27:06.281494",
"modified_by": "Administrator",
"module": "Buying",
"name": "Request for Quotation",
@@ -903,26 +903,6 @@
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Supplier",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
},
{
"amend": 0,
"apply_user_permissions": 0,

View File

@@ -138,7 +138,7 @@ class RequestforQuotation(BuyingController):
'user_fullname': full_name
}
subject = _("Request for Quotation")
subject = _("Request for Quotation: {0}".format(self.name))
template = "templates/emails/request_for_quotation.html"
sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None
message = frappe.get_template(template).render(args)
@@ -204,9 +204,9 @@ def get_list_context(context=None):
return list_context
def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(""" select `tabContact`.name from `tabContact`, `tabDynamic Link`
where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name = %(name)s
or `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
return frappe.db.sql("""select `tabContact`.name from `tabContact`, `tabDynamic Link`
where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s
and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
limit %(start)s, %(page_len)s""", {"start": start, "page_len":page_len, "txt": "%%%s%%" % txt, "name": filters.get('supplier')})
# This method is used to make supplier quotation from material request form.

View File

@@ -27,6 +27,7 @@ QUnit.test("test: request_for_quotation", function(assert) {
{tc_name: 'Test Term 1'}
]);
},
() => frappe.timeout(3),
() => {
assert.ok(cur_frm.doc.transaction_date == date, "Date correct");
assert.ok(cur_frm.doc.company == cur_frm.doc.company, "Company correct");
@@ -38,7 +39,7 @@ QUnit.test("test: request_for_quotation", function(assert) {
assert.ok(cur_frm.doc.message_for_supplier == 'Please supply the specified items at the best possible rates', "Reply correct");
assert.ok(cur_frm.doc.tc_name == 'Test Term 1', "Term name correct");
},
() => frappe.timeout(0.3),
() => frappe.timeout(3),
() => cur_frm.print_doc(),
() => frappe.timeout(1),
() => {
@@ -65,7 +66,7 @@ QUnit.test("test: request_for_quotation", function(assert) {
assert.ok(cur_frm.doc.docstatus == 1, "Quotation request submitted");
},
() => frappe.click_button('Send Supplier Emails'),
() => frappe.timeout(3),
() => frappe.timeout(6),
() => {
assert.ok($('div.modal.fade.in > div.modal-dialog > div > div.modal-body.ui-front > div.msgprint').text().includes("Email sent to supplier Test Supplier"), "Send emails working");
},

View File

@@ -12,7 +12,7 @@ QUnit.test("Test: Request for Quotation", function (assert) {
() => frappe.new_doc("Request for Quotation"),
() => frappe.timeout(1),
() => cur_frm.set_value("transaction_date", "04-04-2017"),
() => cur_frm.set_value("company", "_Test Company"),
() => cur_frm.set_value("company", "For Testing"),
// Add Suppliers
() => {
cur_frm.fields_dict.suppliers.grid.grid_rows[0].toggle_view();
@@ -62,7 +62,7 @@ QUnit.test("Test: Request for Quotation", function (assert) {
},
() => frappe.timeout(2),
() => {
cur_frm.fields_dict.items.grid.grid_rows[0].doc.warehouse = "_Test Warehouse - _TC";
cur_frm.fields_dict.items.grid.grid_rows[0].doc.warehouse = "_Test Warehouse - FT";
},
() => frappe.click_button('Save'),
() => frappe.timeout(1),
@@ -104,7 +104,7 @@ QUnit.test("Test: Request for Quotation", function (assert) {
() => frappe.timeout(1),
() => frappe.click_button('Make Supplier Quotation'),
() => frappe.timeout(1),
() => cur_frm.set_value("company", "_Test Company"),
() => cur_frm.set_value("company", "For Testing"),
() => cur_frm.fields_dict.items.grid.grid_rows[0].doc.rate = 4.99,
() => frappe.timeout(1),
() => frappe.click_button('Save'),

View File

@@ -16,7 +16,7 @@ class Supplier(TransactionBase):
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self, "supplier")
load_address_and_contact(self)
self.load_dashboard_info()
def load_dashboard_info(self):

View File

@@ -13,8 +13,8 @@ QUnit.test("test: supplier", function(assert) {
{credit_days_based_on: 'Fixed Days'},
{accounts: [
[
{'company': "Test Company"},
{'account': "Creditors - TC"}
{'company': "For Testing"},
{'account': "Creditors - FT"}
]]
}
]);
@@ -56,7 +56,8 @@ QUnit.test("test: supplier", function(assert) {
() => frappe.click_button('New Contact'),
() => {
return frappe.tests.set_form_values(cur_frm, [
{first_name: "Contact 3"}
{first_name: "Contact 3"},
{email_id: "test@supplier.com"}
]);
},
() => cur_frm.save(),
@@ -68,7 +69,7 @@ QUnit.test("test: supplier", function(assert) {
assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Name correct");
assert.ok(cur_frm.doc.supplier_type == 'Hardware', "Type correct");
assert.ok(cur_frm.doc.default_currency == 'INR', "Currency correct");
assert.ok(cur_frm.doc.accounts[0].account == 'Creditors - '+frappe.get_abbr('Test Company'), " Account Head abbr correct");
assert.ok(cur_frm.doc.accounts[0].account == 'Creditors - '+frappe.get_abbr('For Testing'), " Account Head abbr correct");
assert.ok($('.address-box:nth-child(3) p').text().includes('Shipping City 3'), "Address correct");
assert.ok($('.col-sm-6+ .col-sm-6 .h6').text().includes('Contact 3'), "Contact correct");
},

View File

@@ -22,7 +22,9 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
cur_frm.page.set_inner_btn_group_as_primary(__("Make"));
cur_frm.add_custom_button(__("Quotation"), this.make_quotation,
__("Make"));
cur_frm.add_custom_button(__('Subscription'), function() {
erpnext.utils.make_subscription(me.frm.doc.doctype, me.frm.doc.name)
}, __("Make"))
}
else if (this.frm.doc.docstatus===0) {

View File

@@ -1676,6 +1676,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment (Company Currency",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1801,6 +1832,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"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": "Rounding Adjustment",
"length": 0,
"no_copy": 1,
"options": "currency",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2051,6 +2113,67 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription_section",
"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": "Subscription Section",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscription",
"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": "Subscription",
"length": 0,
"no_copy": 1,
"options": "Subscription",
"permlevel": 0,
"precision": "",
"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,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -2247,7 +2370,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-07-19 13:51:18.929697",
"modified": "2017-09-19 11:23:25.268924",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",

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