Compare commits

..

178 Commits

Author SHA1 Message Date
Nabin Hait
8c72fa2e4f Merge branch 'develop' 2017-05-19 14:09:00 +05:30
Nabin Hait
0096240a65 bumped to version 8.0.30 2017-05-19 14:38:59 +06:00
Makarand Bauskar
864f134610 [minor] removed the da-DK.csv translations (#8930) 2017-05-19 14:04:52 +05:30
Ayush Shukla
ae696d005a Changed report_hide=0 for reference_name (#8902) 2017-05-19 12:38:08 +05:30
Frappe PR Bot
c080479f1f [translation] translation updates (#8927) 2017-05-19 12:30:04 +05:30
tundebabzy
a109141624 Issue 8842 (#8869)
* adds test that confirms #8842

* fixes #8842 and adds tests

* fixes new test case

* adds test for `encode_company_abbr`

* adds six as a requirement

* fixes six.moves.range import

* fixes duplicate company used in test

* fresh commit of test

* fixes failing test - company not saving

* fixes failing test

* Revert "adds six as a requirement"

This reverts commit 80454d98dc.

* replaces whitespace indentation with tabs
2017-05-19 11:42:45 +05:30
Prateeksha Singh
064530d11f [minor] remove order_type as setter in multiselect (#8906) 2017-05-19 11:09:12 +05:30
Rushabh Mehta
6799e27390 [fix] chart of accounts root sorting, #8784, #8897 (#8904) 2017-05-18 16:21:21 +05:30
gmplab
7607cc9dfa try to fix #997 ,when cart is disabled, it will not show error and it will dedirect to 'contact' page (#8636) 2017-05-18 12:41:19 +05:30
Frappe PR Bot
32e453b8eb [translation] translation updates (#8867) 2017-05-18 12:35:26 +05:30
Nabin Hait
b32cf35fe5 Merge branch 'develop' 2017-05-18 12:01:54 +05:30
Nabin Hait
9422f69fdf bumped to version 8.0.29 2017-05-18 12:31:53 +06:00
Nabin Hait
61ac683847 Fixed chart of accounts for Indonesia (#8900) 2017-05-18 11:58:38 +05:30
Nabin Hait
8fac2ad183 Don't set batch nos automatically on saving, if already set and validate qty with batch (#8887) 2017-05-18 11:54:24 +05:30
Omar Jaber
52e1ba7714 update throw message in maintenance_schedule.py (#8896)
updating Throw message
2017-05-18 11:53:26 +05:30
Nabin Hait
08ea710c8f Minor fix in creating chart of accounts based on existing (#8890) 2017-05-17 19:43:12 +05:30
Nabin Hait
4b544347a9 Hide 'Edit Posting Time' from printing (#8888) 2017-05-17 19:42:38 +05:30
Francisco Roldán
85bfc05efa Fix missing translations (#8871)
* Fix missing translations

* Fix
2017-05-17 19:42:04 +05:30
Nabin Hait
e4f80a6eaa Open lost opportunity again if quotation made against it (#8854) 2017-05-17 19:41:39 +05:30
Rushabh Mehta
f69ffeb0b4 [fix] if rate is greater than price_list_rate, set margin instead of discount. Fixes frappe/erpnext#6468 (#8856) 2017-05-17 19:40:40 +05:30
Faris Ansari
f7a9023fda Show empty state when no students are found in student attendance tool (#8862)
- fixes #8839
2017-05-17 19:37:31 +05:30
Julian Robbins
3d6567411d Spelling improvmement (#8866) 2017-05-17 19:36:15 +05:30
Felipe Orellana
0952df29dc Update product.py (#8877)
Hi!

If template_item_code is None on line 71-72 the query will return ALL "Item Price" records irrespective of item_code, potentially causing the wrong price list rate to be used.

Noticed this behavior when fetching product price for a group of items without "variant_of" data.
2017-05-17 19:20:01 +05:30
Ayush Shukla
76d965f340 [minor]-Changed receivable to payable (#8880) 2017-05-17 19:18:47 +05:30
Ayush Shukla
c55b805b66 [minor] process_payroll_create salary fixed, fixes frappe/erpnext#8853 (#8881)
* [minor] process_payroll_create salary fixed

* [minor] indentation fix
2017-05-17 19:18:26 +05:30
tundebabzy
cf7df5d106 fixes #8883 (#8885) 2017-05-17 19:17:04 +05:30
Sagar Vora
3b04b030eb Fix cost center not getting pulled in DN and SINV (#8878)
* Fixes for getting selling cost center instead of company's default cost center.

* fix error in update_item
2017-05-17 19:16:27 +05:30
Nabin Hait
67ddcf9d32 Merge branch 'develop' 2017-05-17 13:54:04 +05:30
Nabin Hait
def2e4678c bumped to version 8.0.28 2017-05-17 14:24:04 +06:00
Nabin Hait
1e2d7b3519 Filters for multiselect dialog for DN/PR in Sales/Purchase Invoice (#8882) 2017-05-17 13:52:21 +05:30
Nabin Hait
3bd15fb19e Merge branch 'develop' 2017-05-16 13:39:42 +05:30
Nabin Hait
a282c13d84 bumped to version 8.0.27 2017-05-16 14:09:41 +06:00
rohitwaghchaure
a689432a6e [fix] Can't update naming series if format has year,month (#8836) 2017-05-16 12:47:34 +05:30
rohitwaghchaure
3da400b532 [fix] Due Date cannot be before Posting Date during amendement of an invoice (#8841) 2017-05-16 12:43:18 +05:30
Nabin Hait
8a27cf3785 Fix status of invoices with negative outstanding, if no return entry (#8829)
* Move allowance field in Item to the first section to apply it for both stock and non-stock items

* Fix status of invoices with negative outstanding, if no return entry

* get_value included in safe_eval
2017-05-16 12:43:00 +05:30
rohitwaghchaure
73456ac81a [fix] Payments on the invoice is showing even if IS POS option is disabled (#8802) 2017-05-16 11:29:57 +05:30
Saurabh
aa1be1ce92 [documentaion] stripe documentation (#8780) 2017-05-16 09:30:07 +05:30
rohitwaghchaure
654f186f95 [fix] Apply pricing rule on the item based on quantity as per stock uom (#8792) 2017-05-16 08:54:29 +05:30
rohitwaghchaure
09483d3c0f [fix] Numeric keypad not displaying after creation of new customer (#8797) 2017-05-16 08:51:24 +05:30
Makarand Bauskar
5886aafbae [minor] removed cur_frm and added frappe.ui.form.on (#8803) 2017-05-16 08:35:39 +05:30
Charles-Henri Decultot
156eef1907 Description correction (#8811) 2017-05-16 08:34:33 +05:30
Faris Ansari
74e2e4672c Fix for duplicated project dependencies (#8817)
- skip when task is not found
2017-05-16 08:32:45 +05:30
Saurabh
f4ee682400 [fix] pass company filter as string in get_value (#8823) 2017-05-16 08:30:27 +05:30
Makarand Bauskar
475d140b5c [minor] made items table mandatory for quotation (#8825) 2017-05-16 08:26:21 +05:30
Ishan Loya
bdb2f95957 Show duplicate button in BOM unless in draft stage (#8826) 2017-05-16 08:25:07 +05:30
Makarand Bauskar
3e2c9d00f1 [minor] Corrected field label & placed Expense Claim button in Next Step (#8828) 2017-05-16 08:22:45 +05:30
rohitwaghchaure
d678809939 [fix] Party balance field showing wrong currency symbol (#8832) 2017-05-16 08:06:45 +05:30
Manas Solanki
59472e5449 Changes in the student group creation tool (#8833) 2017-05-16 08:05:14 +05:30
Manas Solanki
c5f79d2ec4 Fix for the student batch-wise attendance report (#8834) 2017-05-16 08:00:24 +05:30
Makarand Bauskar
b0df661e81 [minor] set set_posting_time to 1 while data import (#8835) 2017-05-16 07:59:58 +05:30
Rushabh Mehta
939db36ad4 [fix] copy item variant values on save and make non no_copy fields as not editable. fixes frappe/erpnext#4253 (#8837) 2017-05-16 07:42:44 +05:30
Faris Ansari
4fcd8a6db3 Fix sales funnel legend position (Fixes #5073) (#8838) 2017-05-16 07:40:26 +05:30
Faris Ansari
769b6bada8 [POS] Add Pay menu item in mobile view (#8801) (#8845) 2017-05-16 07:31:10 +05:30
Faris Ansari
125996e21c Increase item cart height in mobile view (Fixes #8827) (#8846) 2017-05-16 07:29:15 +05:30
Nabin Hait
7bf810300e Fixed #8822, active students patch 2017-05-15 11:42:37 +05:30
Prateeksha Singh
edeb4dc7e0 Multiselect dialog for getting items (#8583)
* Concatenate docnames and send to mapper

* Multiselect with checkboxes

* set setters as separate filters

* Map filter fields to target_doc

* Get items from quotation (in SO) working

* [major] Set dialog setters for all forms

* Add date field

* Specify non-default date_fields

* [minor] add test_mapper.py

* [minor] remove cur_frm

* [minor][fix] test

* [minor] fix test with make_test_records
2017-05-15 11:32:06 +05:30
Julian Robbins
62e3e75555 Addition of Imap to description of usable mail accounts (#8806) 2017-05-13 09:55:23 +05:30
Saurabh
154385db1b Merge branch 'develop' 2017-05-13 07:42:03 +05:30
Saurabh
82e303882e bumped to version 8.0.26 2017-05-13 08:12:03 +06:00
Saurabh
b679533f81 Merge pull request #8815 from saurabh6790/activation_status_fix
[fix] rename Student Batch to Student Batch Name in activation check
2017-05-13 07:08:02 +05:30
Saurabh
45540569ff [fix] rename Student Batch to Student Batch Name in activation check 2017-05-13 06:30:41 +05:30
Makarand Bauskar
d4e15ca359 [minor] create student batch if does not exists (#8781)
* [minor] create student batch if does not exists

* [fix] minor fixes in if condition
2017-05-12 11:23:58 +05:30
Makarand Bauskar
e8270fe21c [fix] minor fix in get_context for item variants (#8791) 2017-05-12 11:23:23 +05:30
Saurabh
62c7deee00 [fix] don't allow string values in limits to avoid sql injection (#8779) 2017-05-11 18:03:12 +05:30
Nabin Hait
fcefc601e0 Merge branch 'develop' 2017-05-11 17:06:56 +05:30
Nabin Hait
b579fd7ada bumped to version 8.0.25 2017-05-11 17:36:56 +06:00
Nabin Hait
4f5ad50ecf Item Rate in Sales Return must be less than or equal to reference doc (#8775)
* Item Rate in Sales Return must be less than or equal to reference doc

* Fix as rate field is not there in Packed Item
2017-05-11 16:44:19 +05:30
Nabin Hait
5ad6126832 On saving of Accounts Settings, only save enabled warehouses (#8772) 2017-05-11 13:34:04 +05:30
Nabin Hait
62d27ab7d3 Reload doctype bewfore renaming margin fields (#8771) 2017-05-11 13:26:55 +05:30
KanchanChauhan
f74010d379 Calculations based on working and payment days should be made if salary structure exists (#8770) 2017-05-11 11:42:35 +05:30
Makarand Bauskar
0e4c5c9efb [minor] renamed a Total Margin field to Rate With Margin (#8720)
* [minor] renamed a Total Margin field to Rate With Margin

* [minor] minor fixes in field lable
2017-05-11 11:40:02 +05:30
Faris Ansari
734d7795f8 Show party name in General Ledger print report (#8760) 2017-05-11 11:38:30 +05:30
Makarand Bauskar
464f108586 [minor] added currency in Totals for Trial Balance report (#8757)
* [minor] added currency in Totals for Trial Balance report

* [minor] used erpnext.get_default_currency to fetch the company currency
2017-05-10 19:40:36 +05:30
KanchanChauhan
323e46ba5a Added parent filter to the Salary Structure Employee since it was getting base and variable value from first found Salary Structure Employee (#8756) 2017-05-10 17:46:32 +05:30
Makarand Bauskar
62414565b1 [minor] added the address_html field in company doctype (#8754) 2017-05-10 14:52:03 +05:30
Manas Solanki
426b8a14fd Merge the student group and student batch (#8663)
* deleted student batch creation tool

* Patch for deleting the doctype and config

* Changes in the student attendance

* Patch for renaming the student batch as student group

* Changes in the student attendance

* Change in the student attendance reports

- Absent student report
- Student Batch-wise attendance
- Student monthly attendance sheet

* Changes in the patch

* Changes in the course schedule

* Changes in the course scheduling tool

* Change in the assessment plan

* Changes in the assessment result tool

* Cleanup

* Changes in the api.py

* create student group from student batch

* delete student batch

* add patch

* remove student batch from config/schools.py

* Delete the depricated doctype with patch

* Changes in patch

* Changes as per PR
2017-05-09 15:32:52 +05:30
Nabin Hait
0d0d3bacd7 Merge branch 'develop' 2017-05-09 15:13:32 +05:30
Nabin Hait
70e1778712 bumped to version 8.0.24 2017-05-09 15:43:32 +06:00
Nabin Hait
4e6ff8ccd8 Ignore permission for Bin in warehouse query (#8742) 2017-05-09 15:09:10 +05:30
Rushabh Mehta
95233a62d7 [minor] item route item_name + random string 2017-05-09 07:48:41 +05:30
Nabin Hait
226ea7db88 Filter issue on timesheet calendar view (#8730) 2017-05-08 17:34:07 +05:30
Saurabh
9df45bbc42 [fix] Reference Document is required to create Payment Request (#8729)
* [fix] Referene Document is required to create Payment Request

* Update payment_request.py
2017-05-08 17:24:23 +05:30
Rushabh Mehta
a6bc583daf [minor] item route is item name + code 2017-05-08 11:35:40 +05:30
Nabin Hait
3f7fff04f4 Merge branch 'develop' 2017-05-06 13:40:52 +05:30
Nabin Hait
b5a9822fff bumped to version 8.0.23 2017-05-06 14:10:52 +06:00
Nabin Hait
17179ee83a minor syntax fix 2017-05-06 13:23:12 +05:30
Ishan Loya
120ee275cc Fix typo (#8719) 2017-05-06 12:48:22 +05:30
Makarand Bauskar
486045e1d1 [minor] check if date of joining is available before creating Salary Slip (#8700) 2017-05-06 12:47:42 +05:30
Nabin Hait
3257aeeb55 Price list rate fix multiple uom and validation with prev doc (#8718) 2017-05-06 12:47:14 +05:30
Nabin Hait
7228e1af6e Customer/Supplier Name in sales/purchase analytics (#8717) 2017-05-06 12:45:37 +05:30
Nabin Hait
6e7407962f Get exchange rate only if date and currency is present (#8712)
* Get exchange rate only if date and currency is present

* Update transaction.js
2017-05-06 12:45:16 +05:30
Rushabh Mehta
b7e740ff45 [minor] ignore permissions for bin on warehouse_query (#8713) 2017-05-06 12:44:03 +05:30
Dominik Ottenbreit
51cd2df763 Fix Romanian Translation (#8706) 2017-05-05 17:30:45 +05:30
Pawan Mehta
cac94b9bd5 [fix] #8373 (#8707) 2017-05-05 17:29:57 +05:30
Manas Solanki
65c8466622 check for mandatory field before frappe.call (#8705) 2017-05-05 17:28:09 +05:30
Nabin Hait
42343bbc2c Selling price validation against last purchase rate / valuation rate (#8702) 2017-05-05 17:23:17 +05:30
KanchanChauhan
ed56b8afd8 Website route for item based on name not item name (#8682) 2017-05-05 11:56:55 +05:30
Makarand Bauskar
6b3bc8a8e1 [hotfix] fixed the recursion error while saving the User (#8696) 2017-05-05 11:53:00 +05:30
Makarand Bauskar
c4ec937835 [hotfix] fixed object has no attribute 'delivered_by_supplier' (#8699) 2017-05-05 11:52:17 +05:30
Nabin Hait
d2a966eef3 Update general_ledger.py 2017-05-05 10:41:16 +05:30
rohitwaghchaure
6324987c15 [fix] Company's abbreviation change will not update the warehouse (#8685) 2017-05-04 16:12:29 +05:30
Nabin Hait
c9bfb64cd9 Merge branch 'develop' 2017-05-04 12:20:31 +05:30
Nabin Hait
8470b39d4c bumped to version 8.0.22 2017-05-04 12:50:31 +06:00
Nabin Hait
932423ecba Balance Sheet always shows accumulated values from previous fiscal year (#8668) 2017-05-04 12:12:29 +05:30
Faris Ansari
1c09a991f3 Change beta_version to 8.x-beta (#8673)
* Change beta_version to 8.x-beta

* change to 8.x.x-beta
2017-05-04 12:12:14 +05:30
Nabin Hait
fcc0246b38 Get mobile nos for customer contact (#8674) 2017-05-04 12:11:48 +05:30
Nabin Hait
3ce41d6b1f Fixed related to auto fetching batch nos and date valiation in salary structure (#8666)
* Fixed related to auto fetching batch nos and date valiation in salary structure

* Update get_item_details.py
2017-05-03 18:22:24 +05:30
Javier Wong
470535ae9b Removed set_default_roles
set_default_roles was removed in 7fff0908a4

It is not required anymore. It currently breaks the patch.
2017-05-03 16:44:14 +05:30
rohitwaghchaure
a1923574c6 Merge pull request #8657 from rohitwaghchaure/pos_email_id_issue
[fix] Contact not creating if only email id has entered in the POS
2017-05-03 12:56:13 +05:30
Nabin Hait
ef027e9030 Correct args to the fmt_money function 2017-05-03 11:51:47 +05:30
Aditya Duggal
bd8c7d683b Website related fields now consider show_variant_in_website field as well
-Resolves issue #8635
2017-05-03 10:14:09 +05:30
Rohit Waghchaure
fd37516165 [fix] Contact not creating if only email id has entered in the POS 2017-05-02 18:27:09 +05:30
Nabin Hait
504eba7fb2 Test case fixed for Employee Loan Application 2017-05-02 18:19:48 +05:30
Nabin Hait
e15721df48 Caluculate total interest and payable amount in Loan Application if fixed amount per period 2017-05-02 18:19:48 +05:30
mbauskar
c482aeda1a [fixes] added missing get_linked_material_requests method to buying utils 2017-05-02 14:05:54 +05:30
rohitwaghchaure
8811cc6b5b Merge pull request #8651 from rohitwaghchaure/pos_default_customer_issue
[fix] Default pos profile's customer not working for the POS
2017-05-02 13:18:40 +05:30
Rohit Waghchaure
61165127fc [fix] Default pos profile's customer not working for the POS 2017-05-02 13:04:08 +05:30
Nabin Hait
d71a1c5e67 Merge branch 'develop' 2017-05-02 09:58:48 +05:30
Nabin Hait
fb73621db2 bumped to version 8.0.21 2017-05-02 10:28:48 +06:00
Rohit Waghchaure
3df7eef6cc [fix] Unable to create an asset due to rounding issue 2017-05-02 09:49:02 +05:30
akshay
b674d27285 Test Cleanup 2017-05-02 09:48:51 +05:30
akshay
949fbc559e Serial No Rename 2017-05-02 09:48:51 +05:30
Nabin Hait
1117125841 Update domainify.py 2017-05-01 11:40:13 +05:30
mbauskar
e94c6e7b8e [minor] disabled the instructor role if the company domain is not Education 2017-05-01 11:40:13 +05:30
Rushabh Mehta
c75becc42c [minor] README.md and CONTRIBUTING.md 2017-04-28 16:09:57 +05:30
Rushabh Mehta
ed5543adda [minor] README.md and CONTRIBUTING.md 2017-04-28 16:07:36 +05:30
Nabin Hait
a1c23a584d Merge branch 'develop' 2017-04-28 15:34:59 +05:30
Nabin Hait
589927b37d bumped to version 8.0.20 2017-04-28 16:04:58 +06:00
Nabin Hait
2afb9b96cd pricing rule fix 2017-04-28 15:20:49 +05:30
Nabin Hait
8c9fb76854 Remove pricing rules if 'Ignore Pricing Rule' manually triggered 2017-04-28 15:20:49 +05:30
Manas Solanki
0da9bc6309 Fix for program enrollment 2017-04-28 14:37:25 +05:30
Manas Solanki
5a8a5b7d06 Fixes in Student Group 2017-04-28 14:37:25 +05:30
Manas Solanki
71373a176d Configurable validation setting for the student group 2017-04-28 14:37:25 +05:30
mbauskar
1b6270ef40 [hotfix] error while sending the auto email report of Ordered Items To Be Delivered 2017-04-28 14:35:18 +05:30
Rohit Waghchaure
ac28ffb41e [fix] frappe.db.exists('Series', series) is not working because tabSeries table did not have column modified 2017-04-28 14:34:11 +05:30
Rohit Waghchaure
0e6ac8b9b4 Enabled option User Cannot Search for the gl entry doctype 2017-04-28 10:03:18 +05:30
Rohit Waghchaure
07ef5f42c4 [enhance] Show notification for draft state records if doctype is submittable 2017-04-28 09:59:29 +05:30
Nabin Hait
7b04f092a6 Fixed test cases 2017-04-28 09:58:41 +05:30
Nabin Hait
c98f37f91c Patch for reverting manufacturers table from item 2017-04-28 09:58:41 +05:30
Nabin Hait
b6a8920489 Fixed conflict 2017-04-28 09:58:41 +05:30
Nabin Hait
f26dcbc1a6 Merge branch 'develop' 2017-04-26 14:45:37 +05:30
Nabin Hait
ecd46588ec bumped to version 8.0.19 2017-04-26 15:15:37 +06:00
Nabin Hait
96c247c834 Pick batch autmatically only if batch found 2017-04-26 14:37:33 +05:30
Nabin Hait
db8f41ba55 Added Payment documents as Quick Links in SO/PO 2017-04-26 14:34:41 +05:30
Nabin Hait
f7d81c7a7f Merge branch 'develop' 2017-04-25 20:44:54 +05:30
Nabin Hait
5b73a4864a bumped to version 8.0.18 2017-04-25 21:14:54 +06:00
Nabin Hait
85622f9ccb Update update_status_as_paid_for_completed_expense_claim.py 2017-04-25 20:43:29 +05:30
pawan
c27d9f712b Add Report Links 2017-04-25 20:12:55 +05:30
Umair Sayyed
175646572a updated help pages 2017-04-25 16:27:50 +05:30
Nabin Hait
7cfacb315b Merge branch 'RicardoJohann-accumulated_header_std' into develop 2017-04-25 16:26:53 +05:30
Nabin Hait
d5d8db7a3f Cleanup on financial statement PR 2017-04-25 16:26:33 +05:30
Nabin Hait
39bcb3de4b Merge branch 'accumulated_header_std' of https://github.com/RicardoJohann/erpnext into RicardoJohann-accumulated_header_std 2017-04-25 16:13:54 +05:30
Ishan Loya
09fe8e0522 Add bank guarantee to Accounts module display screen 2017-04-25 16:08:22 +05:30
Ishan Loya
17737e4ab1 Change permissions, change account fieldname and add notes section 2017-04-25 16:08:22 +05:30
Ishan Loya
2fca72ae8e Change owner 2017-04-25 16:08:22 +05:30
Ishan Loya
0dbe8547e7 Add screenshot to documentation, change naming series to BG-#####, make Bank Guarantee number unique 2017-04-25 16:08:22 +05:30
Ishan Loya
e1ed5ba726 Remove commented out code 2017-04-25 16:08:22 +05:30
Ishan Loya
0fc57a7df2 Change doctype owner 2017-04-25 16:08:22 +05:30
Ishan Loya
c7a72684fd Add bank guarantee doctype with documentation 2017-04-25 16:08:22 +05:30
Nabin Hait
e0c34bfd77 Merge branch 'PawanMeh-fixes_8466' into develop 2017-04-25 16:05:28 +05:30
Nabin Hait
020dedd00e Cleaned up and commonified the campaign efficiency and lead owner efficiency report 2017-04-25 16:05:01 +05:30
Nabin Hait
28dad095fa Merge branch 'fixes_8466' of https://github.com/PawanMeh/erpnext into PawanMeh-fixes_8466 2017-04-25 15:00:45 +05:30
Nabin Hait
e7125c0ea2 Merge branch 'develop' 2017-04-25 14:30:50 +05:30
Nabin Hait
8590d5b05d bumped to version 8.0.17 2017-04-25 15:00:50 +06:00
sburanaw
66951e528f Fix an import typo in get_item_details.py 2017-04-25 14:09:51 +05:30
Nabin Hait
9b20e07431 [fix] currency field precision 2017-04-25 14:09:29 +05:30
Manas Solanki
d7afa69c6f fix 2017-04-25 14:08:43 +05:30
Manas Solanki
c61dc9c7ea Change in the assessment tool 2017-04-25 14:08:43 +05:30
mbauskar
9cf6d630e9 [minor] fixes for expense claim status 2017-04-25 13:15:50 +05:30
Faris Ansari
5687e2da9d [ui-fix] POS item list 2017-04-24 19:22:05 +05:30
Nabin Hait
e3c122d8c4 AR report: filter based on customer group and credit days based on field. Fixed #8214 2017-04-24 19:06:07 +05:30
Nabin Hait
4cc5e61f60 Update course_schedule.py 2017-04-24 19:00:49 +05:30
Manas Solanki
6293263095 test case fixed 2017-04-24 19:00:49 +05:30
Manas Solanki
810e483757 Changes in the student group 2017-04-24 19:00:49 +05:30
pawan
134487ab2a Changes after review 2017-04-24 13:48:40 +05:30
pawan
7bd7df3742 Changes after review 2017-04-24 13:19:22 +05:30
pawan
83c8ed0827 ”[fix] 2017-04-17 01:02:56 +05:30
Ricardo Johann
033e2fa8b6 changed accumulated header 2017-03-31 02:18:54 -03:00
322 changed files with 54978 additions and 44255 deletions

View File

@@ -1,67 +1,36 @@
## General Overview
### Introduction (first timers)
There are three branches where all the work happens:
Thank you for your interest in raising an Issue with ERPNext. An Issue could mean a bug report or a request for a missing feature. By raising a bug report, you are contributing to the development of ERPNext and this is the first step of participating in the community. Bug reports are very helpful for developers as they quickly fix the issue before other users start facing it.
* **master** - This is the production / stable branch for releases.
* **develop** - This is bleeding edge with features and fixes. Non critical bug fixes and new features go here. All updates to master also get pushed to develop.
* **hotfix** - Urgent bug fixes go here. This is merged into master for releases.
Feature requests are also a great way to take the product forward. New ideas can come in any user scenario and the issue list also acts a roadmap of future features.
## Release Cycles
When you are raising an Issue, you should keep a few things in mind. Remember that the developer does not have access to your machine so you must give all the information you can while raising an Issue. If you are suggesting a feature, you should be very clear about what you want.
Usually, hotfix / develop is pushed to master roughly every week.
The Issue list is not the right place to ask a question or start a general discussion. If you want to do that , then the right place is the forum [https://discuss.erpnext.com](https://discuss.erpnext.com).
If we are close to a major release, then all bugfixes get pushed to hotfix and a release is done every week or as necessary.
### Reply and Closing Policy
***
If your issue is not clear or does not meet the guidelines, then it will be closed. If it is closed, please supply the information asked and re-open it.
### General Issue Guidelines
## Contributing
1. **Search existing Issues:** Before raising a Issue, search if it has been raised before. Maybe add a 👍 or give additional help by creating a mockup if it is not already created.
1. **Report each issue separately:** Don't club multiple, unreleated issues in one note.
1. **Brief:** Please don't include long explanations. Use screenshots and bullet points instead of descriptive paragraphs.
Contributing to ERPNext is not very different from the usual Pull Request workflow on GitHub.
### Bug Report Guidelines
### Prerequisites :
1. **Steps to Reproduce:** The bug report must have a list of steps needed to reproduce a bug. If we cannot reproduce it, then we cannot solve it.
1. **Version Number:** Please add the version number in your report. Often a bug is fixed in the latest version
1. **Clear Title:** Add a clear subject to your bug report like "Unable to submit Purchase Order without Basic Rate" instead of just "Cannot Submit"
1. **Screenshots:** Screenshots are a great way of communicating the issues. Try adding annotations or using LiceCAP to take a screencast in `gif`.
* You need to know [Git and Github basics](https://try.github.io/levels/1/challenges/1)
* You need to have a Fork of the [ERPNext repo](https://github.com/frappe/erpnext) in your personal Github account
* You need to add a [remote](#glossary) for your Forked repository. `git remote add origin [your-erpnext-repo-url]`
### Feature Request Guidelines
### The Process:
1. **Clarity:** Clearly specify how do you want the feature to behave. Don't just say "I would like multiple PDF formats", say that "Ability to add multiple print formats for customers with different languages".
1. **Solution:** Try and identify how the feature should look like.
1. **Mockups:** Mockups are a great way to explain your requirement.
1. Make sure you're in the right branch. **develop** for adding features / fixing issues and **hotfix** for urgent bug fixes
2. Make your changes
3. Create and checkout a new branch for the changes you've made. `git checkout -b [branch-name]`
4. Add and commit your changes `git commit -am "[commit-message]"
5. If you have been working on sometime for a long time, you should [rebase](#glossary) your branch with main develop branch. `git pull upstream develop --rebase` where `upstream` is the remote name of our repo
6. Now, push your changes to your fork. `git push origin [branch-name]`
If you rebased your commits, you will have to [force push](http://vignette2.wikia.nocookie.net/starwars/images/e/ea/Yodapush.png/revision/latest?cb=20130205190454) `git push origin [branch-name] --force`
7. You should now be able to see your pushed branch on Github, now create a pull request against the branch that you want to merge to.
8. Wait for us to review it
### What if my Issue is closed
### Your Pull Request Should have
1. Clear explanation of the use case
1. Screenshots / Screecast GIF
1. Test Cases (if applicable)
1. Update to documentation
### Common Problems:
* During rebase you might face _merge conflicts_. A merge conflict occurs when you have made changes to the same file that someone else has, in the commits you're pulling. You need to resolve these conflicts by picking which code you want to keep, yours or theirs. You can use `git mergetool` for help.
* Sometimes you don't have a local branch to which you want to make changes to. In that case you first run `git fetch` followed by `git checkout --track -b upstream/[branch-name]`
### Good practices:
* You should rebase your branch with the branch you plan to make a Pull Request (PR) to as often as you can.
* Your commit messages should be precise and explain exactly what the commit does. Same goes for the Pull Request title.
* When making a PR make sure that all your code is committed properly by checking the diffs.
* If you're working on different things at the same time, make sure you make separate branches for each.
* Don't create new DocTypes unless absolutely necessary. If you find that there is a another DocType with a similar functionality, then please try and extend that functionality.
* DRY. Don't Repeat Yourself. Before writing up a similar function /feature make sure it doesn't exist in the codebase already.
* Tabs, not spaces.
### Glossary
* remote - A remote is a connection to a Github repo. You should have two remotes, one that points to your repo and one to ours.
* rebase - When you rebase a branch, you pull commits from your remote branch and move your commits on top of it. This allows you to update your branch with the latest changes without losing your changes.
Don't worry, take the feedback, supply the correct information and re-open it!

View File

@@ -40,7 +40,8 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document
## Contributing
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Pull-Request-Guidelines)
1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
1. [Translations](https://translate.erpnext.com)
1. [Chart of Accounts](https://charts.erpnext.com)

View File

@@ -2,7 +2,8 @@
from __future__ import unicode_literals
import frappe
__version__ = '8.0.16'
__version__ = '8.0.30'
def get_default_company(user=None):
'''Get default company for user'''
@@ -19,12 +20,14 @@ def get_default_company(user=None):
return default_company
def get_default_currency():
'''Returns the currency of the default company'''
company = get_default_company()
if company:
return frappe.db.get_value('Company', company, 'default_currency')
def get_company_currency(company):
'''Returns the default company currency'''
if not frappe.flags.company_currency:
@@ -33,11 +36,13 @@ def get_company_currency(company):
frappe.flags.company_currency[company] = frappe.db.get_value('Company', company, 'default_currency')
return frappe.flags.company_currency[company]
def set_perpetual_inventory(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.auto_accounting_for_stock = enable
accounts_settings.save()
def encode_company_abbr(name, company):
'''Returns name encoded with company abbreviation'''
company_abbr = frappe.db.get_value("Company", company, "abbr")
@@ -46,4 +51,6 @@ def encode_company_abbr(name, company):
if parts[-1].lower() != company_abbr.lower():
parts.append(company_abbr)
return " - ".join([parts[0], company_abbr])
return " - ".join(parts)

View File

@@ -188,9 +188,9 @@ class Account(Document):
account_balance = get_balance_on(self.name)
if account_balance != stock_balance:
frappe.throw(_('Account balance ({0}) and stock value ({1}) must be same')\
.format(fmt_money(account_balance, self.account_currency),
fmt_money(stock_balance, self.account_currency)))
frappe.throw(_('Account balance ({0}) for {1} and stock value ({2}) for warehouse {3} must be same')
.format(fmt_money(account_balance, currency=self.account_currency), self.name,
fmt_money(stock_balance, currency=self.account_currency), self.warehouse))
elif self.warehouse:
self.warehouse = None

View File

@@ -125,13 +125,14 @@ def get_account_tree_from_existing_company(existing_company):
account_tree = {}
# fill in tree starting with root accounts (those with no parent)
build_account_tree(account_tree, None, all_accounts)
if all_accounts:
build_account_tree(account_tree, None, all_accounts)
return account_tree
def build_account_tree(tree, parent, all_accounts):
# find children
parent_account = parent.name if parent else None
children = [acc for acc in all_accounts if acc.parent_account == parent_account]
parent_account = parent.name if parent else ""
children = [acc for acc in all_accounts if cstr(acc.parent_account) == parent_account]
# if no children, but a group account
if not children and parent.is_group:

View File

@@ -22,20 +22,10 @@
},
"1120.000 Bank ": {
"1121.000 Bank Rupiah": {
"1121.0010 Bank 1": {
"account_type": "Bank"
},
"1121.0020 Bank 2": {
"account_type": "Bank"
}
"is_group": 1
},
"1122.000 Bank Other Currency": {
"1122.0010 Bank 1": {
"account_type": "Bank"
},
"1122.0020 Bank 2": {
"account_type": "Bank"
}
"is_group": 1
},
"account_type": "Bank"
},

View File

@@ -21,10 +21,13 @@ class AccountsSettings(Document):
company.save()
# Create account head for warehouses
warehouse_list = frappe.db.sql("select name, company from tabWarehouse", as_dict=1)
warehouse_list = frappe.db.sql("""select name, company from tabWarehouse
where disabled=0""", as_dict=1)
warehouse_with_no_company = [d.name for d in warehouse_list if not d.company]
if warehouse_with_no_company:
frappe.throw(_("Company is missing in warehouses {0}").format(comma_and(warehouse_with_no_company)))
frappe.throw(_("Company is missing in warehouses {0}")
.format(comma_and(warehouse_with_no_company)))
for wh in warehouse_list:
wh_doc = frappe.get_doc("Warehouse", wh.name)
wh_doc.flags.ignore_permissions = True

View File

@@ -45,7 +45,7 @@ frappe.ui.form.on('Asset', {
erpnext.asset.scrap_asset(frm);
});
frm.add_custom_button("Sale Asset", function() {
frm.add_custom_button("Sell Asset", function() {
erpnext.asset.make_sales_invoice(frm);
});

View File

@@ -114,8 +114,17 @@ class Asset(Document):
def set_accumulated_depreciation(self):
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
for d in self.get("schedules"):
accumulated_depreciation += flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation = flt(self.value_after_depreciation)
for i, d in enumerate(self.get("schedules")):
depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount"))
value_after_depreciation -= flt(depreciation_amount)
if i==len(self.get("schedules"))-1 and self.depreciation_method == "Straight Line":
depreciation_amount += flt(value_after_depreciation - flt(self.expected_value_after_useful_life),
d.precision("depreciation_amount"))
d.depreciation_amount = depreciation_amount
accumulated_depreciation += d.depreciation_amount
d.accumulated_depreciation_amount = flt(accumulated_depreciation, d.precision("accumulated_depreciation_amount"))
def get_depreciation_amount(self, depreciable_value):

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import unittest
from frappe.utils import cstr, nowdate, getdate
from frappe.utils import cstr, nowdate, getdate, flt
from erpnext.accounts.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
from erpnext.accounts.doctype.asset.asset import make_sales_invoice, make_purchase_invoice
@@ -243,6 +243,23 @@ class TestAsset(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Asset", "Macbook Pro 1", "status"), "Partially Depreciated")
def test_asset_expected_value_after_useful_life(self):
asset = frappe.get_doc("Asset", "Macbook Pro 1")
asset.depreciation_method = "Straight Line"
asset.is_existing_asset = 1
asset.total_number_of_depreciations = 400
asset.gross_purchase_amount = 16866177.00
asset.expected_value_after_useful_life = 500000
asset.save()
accumulated_depreciation_after_full_schedule = \
max([d.accumulated_depreciation_amount for d in asset.get("schedules")])
asset_value_after_full_schedule = (flt(asset.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule))
self.assertTrue(asset.expected_value_after_useful_life >= asset_value_after_full_schedule)
def tearDown(self):
asset = frappe.get_doc("Asset", "Macbook Pro 1")

View File

@@ -0,0 +1,30 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Bank Guarantee', {
refresh: function(frm) {
cur_frm.set_query("account", function() {
return {
"filters": {
"account_type": "Bank",
"is_group": 0
}
};
});
cur_frm.set_query("project", function() {
return {
"filters": {
"customer": cur_frm.doc.customer
}
};
});
},
start_date: function(frm) {
end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date);
},
validity: function(frm) {
end_date = frappe.datetime.add_days(cur_frm.doc.start_date, cur_frm.doc.validity - 1);
cur_frm.set_value("end_date", end_date);
}
});

View File

@@ -1,35 +1,37 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "",
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "BG-.#####",
"beta": 0,
"creation": "2016-07-21 15:49:53.776461",
"creation": "2016-12-17 10:43:35.731631",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"document_type": "Document",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "student_batch_name",
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Student Batch Name",
"label": "Customer",
"length": 0,
"no_copy": 0,
"options": "Student Batch Name",
"options": "Customer",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -43,11 +45,12 @@
"unique": 0
},
{
"allow_on_submit": 0,
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "academic_year",
"fieldname": "project",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -55,41 +58,11 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Academic Year",
"length": 0,
"no_copy": 0,
"options": "Academic Year",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1",
"fieldname": "enabled",
"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": "Active",
"label": "Project",
"length": 0,
"no_copy": 0,
"options": "Project",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -103,11 +76,73 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_2",
"fieldname": "account",
"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": "Bank Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -131,23 +166,23 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "program",
"fieldtype": "Link",
"fieldname": "start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Program",
"in_standard_filter": 0,
"label": "Start Date",
"length": 0,
"no_copy": 0,
"options": "Program",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -161,11 +196,163 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "academic_term",
"description": "",
"fieldname": "validity",
"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": "Validity in 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": 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": "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": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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": "bank_guarantee_number",
"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": "Bank Guarantee Number",
"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": 1
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"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,
"label": "More Information",
"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": "more_information",
"fieldtype": "Text Editor",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Notes",
"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": "amended_from",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -173,134 +360,15 @@
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Academic Term",
"length": 0,
"no_copy": 0,
"options": "Academic Term",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_6",
"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": "Students",
"label": "Amended From",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Bank Guarantee",
"permlevel": 0,
"precision": "",
"print_hide": 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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "students",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Students",
"length": 0,
"no_copy": 0,
"options": "Student Batch Student",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Instructors",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "instructors",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Instructors",
"length": 0,
"no_copy": 0,
"options": "Student Batch Instructor",
"permlevel": 0,
"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,
@@ -309,20 +377,20 @@
"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,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 17:17:00.460594",
"modified": "2017-04-25 13:31:49.627831",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Batch",
"module": "Accounts",
"name": "Bank Guarantee",
"name_case": "",
"owner": "Administrator",
"permissions": [
@@ -331,49 +399,50 @@
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"delete": 0,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "Instructor",
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"share": 1,
"submit": 1,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "customer",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "",
"title_field": "customer",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -6,5 +6,5 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class AssessmentCode(Document):
class BankGuarantee(Document):
pass

View File

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
import unittest
# test_records = frappe.get_test_records('Student Batch')
# test_records = frappe.get_test_records('Bank Guarantee')
class TestStudentBatch(unittest.TestCase):
class TestBankGuarantee(unittest.TestCase):
pass

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "GL.#######",
@@ -12,6 +13,7 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -22,6 +24,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Posting Date",
@@ -41,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -51,6 +55,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Transaction Date",
@@ -70,6 +75,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -80,6 +86,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Account",
@@ -100,6 +107,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -110,6 +118,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Party Type",
@@ -128,6 +137,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -138,6 +148,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Party",
@@ -156,6 +167,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -166,6 +178,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Cost Center",
@@ -186,6 +199,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -196,6 +210,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Debit Amount",
@@ -217,6 +232,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -227,6 +243,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Credit Amount",
@@ -248,6 +265,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -258,6 +276,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Account Currency",
@@ -277,6 +296,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -287,6 +307,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Debit Amount in Account Currency",
@@ -306,6 +327,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -316,6 +338,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Credit Amount in Account Currency",
@@ -335,6 +358,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -345,6 +369,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Against",
@@ -364,6 +389,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -374,6 +400,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Against Voucher Type",
@@ -394,6 +421,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -404,6 +432,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Against Voucher",
@@ -424,6 +453,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -434,6 +464,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Voucher Type",
@@ -454,6 +485,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -464,6 +496,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1,
"label": "Voucher No",
@@ -484,6 +517,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -494,6 +528,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Project",
@@ -513,6 +548,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -523,6 +559,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Remarks",
@@ -542,6 +579,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -552,6 +590,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Opening",
@@ -572,6 +611,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -582,6 +622,7 @@
"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 Advance",
@@ -602,6 +643,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -612,6 +654,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fiscal Year",
@@ -632,6 +675,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -642,6 +686,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company",
@@ -662,18 +707,18 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-list",
"idx": 1,
"image_view": 0,
"in_create": 1,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-12-15 14:44:41.098790",
"modified": "2017-04-27 13:18:06.617940",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
@@ -689,7 +734,6 @@
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -710,7 +754,6 @@
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -731,7 +774,6 @@
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 0,
"read": 1,
@@ -744,10 +786,12 @@
}
],
"quick_entry": 1,
"read_only": 0,
"read_only": 1,
"read_only_onload": 0,
"search_fields": "voucher_no,account,posting_date,against_voucher",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}

View File

@@ -514,7 +514,7 @@ class JournalEntry(AccountsController):
def update_expense_claim(self):
for d in self.accounts:
if d.reference_type=="Expense Claim" and d.party:
if d.reference_type=="Expense Claim" and d.reference_name:
doc = frappe.get_doc("Expense Claim", d.reference_name)
update_reimbursed_amount(doc)

View File

@@ -147,6 +147,7 @@ frappe.ui.form.on('Payment Entry', {
var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency"
frm.set_df_property("total_allocated_amount", "options", currency_field);
frm.set_df_property("unallocated_amount", "options", currency_field);
frm.set_df_property("party_balance", "options", currency_field);
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
party_account_currency, "references");

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "naming_series:",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,6 +45,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,
@@ -103,6 +107,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -132,6 +137,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -161,6 +167,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,
@@ -219,6 +227,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -249,6 +258,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -280,6 +290,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -311,6 +322,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -341,6 +353,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -369,6 +382,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -398,6 +412,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -428,6 +443,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -457,6 +473,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -486,6 +503,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -516,6 +534,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -546,6 +565,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -576,6 +596,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -605,6 +626,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -635,6 +657,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -658,13 +681,14 @@
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 1,
"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,
@@ -694,17 +718,17 @@
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"in_dialog": 0,
"in_create": 1,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-23 05:03:37.464863",
"modified": "2017-05-18 12:18:39.187714",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",

View File

@@ -14,9 +14,14 @@ from frappe.integrations.utils import get_payment_gateway_controller
class PaymentRequest(Document):
def validate(self):
self.validate_reference_document()
self.validate_payment_request()
self.validate_currency()
def validate_reference_document(self):
if not self.reference_doctype or not self.reference_name:
frappe.throw(_("To create a Payment Request reference document is required"))
def validate_payment_request(self):
if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
"name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):

View File

@@ -145,8 +145,8 @@ def get_pricing_rule_for_item(args):
})
if args.ignore_pricing_rule or not args.item_code:
if args.get("pricing_rule"):
item_details = remove_pricing_rule(args, item_details)
if frappe.db.exists(args.doctype, args.name) and args.get("pricing_rule"):
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
return item_details
if not (args.item_group and args.brand):
@@ -187,12 +187,13 @@ def get_pricing_rule_for_item(args):
else:
item_details.discount_percentage = pricing_rule.discount_percentage
elif args.get('pricing_rule'):
item_details = remove_pricing_rule(args, item_details)
item_details = remove_pricing_rule_for_item(args.get("pricing_rule"), item_details)
return item_details
def remove_pricing_rule(args, item_details):
pricing_rule = frappe.db.get_value('Pricing Rule', args.get('pricing_rule'), ['price_or_discount', 'margin_type'], as_dict=1)
def remove_pricing_rule_for_item(pricing_rule, item_details):
pricing_rule = frappe.db.get_value('Pricing Rule', pricing_rule,
['price_or_discount', 'margin_type'], as_dict=1)
if pricing_rule and pricing_rule.price_or_discount == 'Discount Percentage':
item_details.discount_percentage = 0.0
@@ -200,8 +201,22 @@ def remove_pricing_rule(args, item_details):
item_details.margin_rate_or_amount = 0.0
item_details.margin_type = None
if item_details.pricing_rule:
item_details.pricing_rule = None
return item_details
@frappe.whitelist()
def remove_pricing_rules(item_list):
if isinstance(item_list, basestring):
item_list = json.loads(item_list)
out = []
for item in item_list:
item = frappe._dict(item)
out.append(remove_pricing_rule_for_item(item.get("pricing_rule"), item))
return out
def get_pricing_rules(args):
def _get_tree_conditions(parenttype, allow_blank=True):
field = frappe.scrub(parenttype)
@@ -270,9 +285,10 @@ def get_pricing_rules(args):
def filter_pricing_rules(args, pricing_rules):
# filter for qty
stock_qty = args.get('qty') * args.get('conversion_factor', 1)
if pricing_rules:
pricing_rules = filter(lambda x: (flt(args.get("qty"))>=flt(x.min_qty)
and (flt(args.get("qty"))<=x.max_qty if x.max_qty else True)), pricing_rules)
pricing_rules = filter(lambda x: (flt(stock_qty)>=flt(x.min_qty)
and (flt(stock_qty)<=x.max_qty if x.max_qty else True)), pricing_rules)
# add variant_of property in pricing rule
for p in pricing_rules:

View File

@@ -5,6 +5,9 @@
from __future__ import unicode_literals
import unittest
import frappe
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.get_item_details import get_item_details
from frappe import MandatoryError
class TestPricingRule(unittest.TestCase):
def test_pricing_rule_for_discount(self):
@@ -203,3 +206,46 @@ class TestPricingRule(unittest.TestCase):
details = get_item_details(args)
self.assertEquals(details.get("discount_percentage"), 17.5)
def test_pricing_rule_for_stock_qty(self):
frappe.db.sql("delete from `tabPricing Rule`")
test_record = {
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule",
"apply_on": "Item Code",
"item_code": "_Test Item",
"selling": 1,
"price_or_discount": "Discount Percentage",
"price": 0,
"min_qty": 5,
"max_qty": 7,
"discount_percentage": 17.5,
"company": "_Test Company"
}
frappe.get_doc(test_record.copy()).insert()
if not frappe.db.get_value('UOM Conversion Detail',
{'parent': '_Test Item', 'uom': 'box'}):
item = frappe.get_doc('Item', '_Test Item')
item.append('uoms', {
'uom': 'Box',
'conversion_factor': 5
})
item.save(ignore_permissions=True)
# With pricing rule
so = make_sales_order(item_code="_Test Item", qty=1, uom="Box", do_not_submit=True)
so.items[0].price_list_rate = 100
so.submit()
so = frappe.get_doc('Sales Order', so.name)
self.assertEquals(so.items[0].discount_percentage, 17.5)
self.assertEquals(so.items[0].rate, 82.5)
# Without pricing rule
so = make_sales_order(item_code="_Test Item", qty=2, uom="Box", do_not_submit=True)
so.items[0].price_list_rate = 100
so.submit()
so = frappe.get_doc('Sales Order', so.name)
self.assertEquals(so.items[0].discount_percentage, 0)
self.assertEquals(so.items[0].rate, 100)

View File

@@ -49,29 +49,38 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
}
if(doc.docstatus===0) {
cur_frm.add_custom_button(__('Purchase Order'), function() {
var me = this;
this.frm.add_custom_button(__('Purchase Order'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
source_doctype: "Purchase Order",
target: me.frm,
setters: {
supplier: me.frm.doc.supplier || undefined,
},
get_query_filters: {
supplier: cur_frm.doc.supplier || undefined,
docstatus: 1,
status: ["!=", "Closed"],
per_billed: ["<", 99.99],
company: cur_frm.doc.company
company: me.frm.doc.company
}
})
}, __("Get items from"));
cur_frm.add_custom_button(__('Purchase Receipt'), function() {
this.frm.add_custom_button(__('Purchase Receipt'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
source_doctype: "Purchase Receipt",
target: me.frm,
date_field: "posting_date",
setters: {
supplier: me.frm.doc.supplier || undefined,
},
get_query_filters: {
supplier: cur_frm.doc.supplier || undefined,
docstatus: 1,
status: ["!=", "Closed"],
company: cur_frm.doc.company
company: me.frm.doc.company,
is_return: 0
}
})
}, __("Get items from"));
@@ -120,7 +129,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
if(!this.frm.doc.company) {
cur_frm.set_value("is_paid", 0)
this.frm.set_value("is_paid", 0)
msgprint(__("Please specify Company to proceed"));
}
}

View File

@@ -13,6 +13,7 @@
"editable_grid": 0,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -43,6 +44,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,6 +76,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -105,6 +108,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -136,6 +140,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -166,6 +171,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -195,6 +201,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -224,6 +231,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -253,6 +261,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -284,6 +293,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -315,6 +325,7 @@
"width": "100px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -334,7 +345,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@@ -345,6 +356,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -376,6 +388,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -406,6 +419,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -437,6 +451,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -465,6 +480,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -495,6 +511,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -525,6 +542,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -555,6 +573,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -586,6 +605,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -615,6 +635,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -644,6 +665,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -673,6 +695,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -702,6 +725,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -730,6 +754,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -758,6 +783,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -786,6 +812,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -814,6 +841,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -845,6 +873,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -874,6 +903,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -903,6 +933,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -934,6 +965,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -966,6 +998,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -993,6 +1026,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1022,6 +1056,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1051,6 +1086,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1080,6 +1116,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1108,6 +1145,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1138,6 +1176,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1168,6 +1207,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1199,6 +1239,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1226,6 +1267,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1256,6 +1298,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1288,6 +1331,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1315,6 +1359,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1345,6 +1390,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1376,6 +1422,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1406,6 +1453,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1437,6 +1485,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1468,6 +1517,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1497,6 +1547,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1527,6 +1578,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1558,6 +1610,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1589,6 +1642,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1620,6 +1674,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1648,6 +1703,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1679,6 +1735,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1710,6 +1767,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1740,6 +1798,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1770,6 +1829,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1801,6 +1861,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1831,6 +1892,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1859,6 +1921,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1888,6 +1951,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1918,6 +1982,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1946,6 +2011,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1977,6 +2043,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2008,6 +2075,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2037,6 +2105,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2068,6 +2137,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2098,6 +2168,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2129,6 +2200,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2160,6 +2232,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2191,6 +2264,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2221,6 +2295,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2251,6 +2326,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2279,6 +2355,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2310,6 +2387,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2340,6 +2418,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2371,6 +2450,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2400,6 +2480,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2430,6 +2511,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2458,6 +2540,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2488,6 +2571,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2518,6 +2602,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2549,6 +2634,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2579,6 +2665,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2610,6 +2697,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2640,6 +2728,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2669,6 +2758,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2697,6 +2787,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2726,6 +2817,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2757,6 +2849,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2789,6 +2882,7 @@
"width": "50px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2819,6 +2913,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2848,6 +2943,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2878,6 +2974,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2909,6 +3006,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2938,6 +3036,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2968,6 +3067,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3000,6 +3100,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3030,6 +3131,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3063,6 +3165,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3093,6 +3196,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3120,6 +3224,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3151,6 +3256,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3181,6 +3287,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3212,6 +3319,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -3243,6 +3351,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3273,6 +3382,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3304,6 +3414,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3334,6 +3445,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3364,6 +3476,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3394,6 +3507,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3425,6 +3539,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3455,6 +3570,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3485,6 +3601,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3513,6 +3630,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3543,6 +3661,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3573,6 +3692,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -3603,6 +3723,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -3646,7 +3767,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-04-10 12:05:28.082020",
"modified": "2017-05-17 10:35:40.729350",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",

View File

@@ -204,7 +204,7 @@ class PurchaseInvoice(BuyingController):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
for d in self.get('items'):
if not d.purchase_order:
throw(_("Purchse Order number required for Item {0}").format(d.item_code))
throw(_("Purchase Order number required for Item {0}").format(d.item_code))
def pr_required(self):
stock_items = self.get_stock_items()

View File

@@ -325,8 +325,10 @@ def make_customer_and_address(customers):
if not frappe.db.exists('Customer', name):
name = add_customer(name)
data = json.loads(data)
make_contact(data, name)
make_address(data, name)
customer_list.append(name)
frappe.db.commit()
return customer_list
def add_customer(name):
@@ -340,6 +342,29 @@ def add_customer(name):
frappe.db.commit()
return customer_doc.name
def make_contact(args,customer):
if args.get('email_id') or args.get('phone'):
name = frappe.db.get_value('Dynamic Link',
{'link_doctype': 'Customer', 'link_name': customer, 'parenttype': 'Contact'}, 'parent')
args = {
'email_id': args.get('email_id'),
'phone': args.get('phone')
}
doc = frappe.new_doc('Contact')
if name:
doc = frappe.get_doc('Contact', name)
doc.update(args)
if not name:
doc.first_name = customer
doc.append('links',{
'link_doctype': 'Customer',
'link_name': customer
})
doc.save(ignore_permissions=True)
def make_address(args, customer):
if not args.get('address_line1'): return

View File

@@ -112,33 +112,44 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
},
sales_order_btn: function() {
this.$sales_order_btn = cur_frm.add_custom_button(__('Sales Order'),
var me = this;
this.$sales_order_btn = this.frm.add_custom_button(__('Sales Order'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
source_doctype: "Sales Order",
target: me.frm,
setters: {
customer: me.frm.doc.customer || undefined,
},
get_query_filters: {
docstatus: 1,
status: ["!=", "Closed"],
per_billed: ["<", 99.99],
customer: cur_frm.doc.customer || undefined,
company: cur_frm.doc.company
company: me.frm.doc.company
}
})
}, __("Get items from"));
},
delivery_note_btn: function() {
this.$delivery_note_btn = cur_frm.add_custom_button(__('Delivery Note'),
var me = this;
this.$delivery_note_btn = this.frm.add_custom_button(__('Delivery Note'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
source_doctype: "Delivery Note",
target: me.frm,
date_field: "posting_date",
setters: {
customer: me.frm.doc.customer || undefined
},
get_query: function() {
var filters = {
company: cur_frm.doc.company
docstatus: 1,
company: me.frm.doc.company
};
if(cur_frm.doc.customer) filters["customer"] = cur_frm.doc.customer;
if(me.frm.doc.customer) filters["customer"] = me.frm.doc.customer;
return {
query: "erpnext.controllers.queries.get_delivery_notes_to_be_billed",
filters: filters

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@ from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amou
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
from erpnext.accounts.doctype.asset.depreciation \
import get_disposal_account_and_cost_center, get_gl_entries_on_asset_disposal
from erpnext.stock.doctype.batch.batch import set_batch_nos
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -52,7 +53,7 @@ class SalesInvoice(SellingController):
def validate(self):
super(SalesInvoice, self).validate()
self.validate_posting_time()
self.validate_auto_set_posting_time()
self.so_dn_required()
self.validate_proj_cust()
self.validate_with_previous_doc()
@@ -78,6 +79,10 @@ class SalesInvoice(SellingController):
if not self.is_opening:
self.is_opening = 'No'
if self._action != 'submit' and self.update_stock and not self.is_return:
set_batch_nos(self, 'warehouse', True)
self.set_against_income_account()
self.validate_c_form()
@@ -87,7 +92,7 @@ class SalesInvoice(SellingController):
self.set_billing_hours_and_amount()
self.update_timesheet_billing_for_project()
self.set_status()
def before_save(self):
set_account_for_mode_of_payment(self)
@@ -330,7 +335,7 @@ class SalesInvoice(SellingController):
frappe.throw(_("Debit To account must be a Receivable account"))
self.party_account_currency = account.account_currency
def clear_unallocated_mode_of_payments(self):
self.set("payments", self.get("payments", {"amount": ["not in", [0, None, ""]]}))
@@ -341,13 +346,23 @@ class SalesInvoice(SellingController):
super(SalesInvoice, self).validate_with_previous_doc({
"Sales Order": {
"ref_dn_field": "sales_order",
"compare_fields": [["customer", "="], ["company", "="], ["project", "="],
["currency", "="]],
"compare_fields": [["customer", "="], ["company", "="], ["project", "="], ["currency", "="]]
},
"Sales Order Item": {
"ref_dn_field": "so_detail",
"compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]],
"is_child_table": True,
"allow_duplicate_prev_row_id": True
},
"Delivery Note": {
"ref_dn_field": "delivery_note",
"compare_fields": [["customer", "="], ["company", "="], ["project", "="],
["currency", "="]],
"compare_fields": [["customer", "="], ["company", "="], ["project", "="], ["currency", "="]]
},
"Delivery Note Item": {
"ref_dn_field": "dn_detail",
"compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]],
"is_child_table": True,
"allow_duplicate_prev_row_id": True
},
})
@@ -368,6 +383,12 @@ class SalesInvoice(SellingController):
def add_remarks(self):
if not self.remarks: self.remarks = 'No Remarks'
def validate_auto_set_posting_time(self):
# Don't auto set the posting date and time if invoice is amended
if self.is_new() and self.amended_from:
self.set_posting_time = 1
self.validate_posting_time()
def so_dn_required(self):
"""check in manage account if sales order / delivery note required or not."""
@@ -535,7 +556,7 @@ class SalesInvoice(SellingController):
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
return
if not gl_entries:
gl_entries = self.get_gl_entries()
@@ -681,7 +702,7 @@ class SalesInvoice(SellingController):
else payment_mode.amount
}, payment_mode_account_currency)
)
def make_gle_for_change_amount(self, gl_entries):
if cint(self.is_pos) and self.change_amount:
if self.account_for_change_amount:
@@ -698,7 +719,7 @@ class SalesInvoice(SellingController):
"against_voucher_type": self.doctype
}, self.party_account_currency)
)
gl_entries.append(
self.get_gl_dict({
"account": self.account_for_change_amount,
@@ -708,7 +729,7 @@ class SalesInvoice(SellingController):
)
else:
frappe.throw(_("Select change amount account"), title="Mandatory Field")
def make_write_off_gl_entry(self, gl_entries):
# write off entries, applicable if only pos
if self.write_off_account and self.write_off_amount:
@@ -792,7 +813,7 @@ def make_delivery_note(source_name, target_doc=None):
def update_item(source_doc, target_doc, source_parent):
target_doc.qty = flt(source_doc.qty) - flt(source_doc.delivered_qty)
target_doc.stock_qty = target_doc.qty * flt(source_doc.conversion_factor)
target_doc.base_amount = target_doc.qty * flt(source_doc.base_rate)
target_doc.amount = target_doc.qty * flt(source_doc.rate)
@@ -810,7 +831,8 @@ def make_delivery_note(source_name, target_doc=None):
"parent": "against_sales_invoice",
"serial_no": "serial_no",
"sales_order": "against_sales_order",
"so_detail": "so_detail"
"so_detail": "so_detail",
"cost_center": "cost_center"
},
"postprocess": update_item,
"condition": lambda doc: doc.delivered_by_supplier!=1
@@ -839,4 +861,4 @@ def make_sales_return(source_name, target_doc=None):
def set_account_for_mode_of_payment(self):
for data in self.payments:
if not data.account:
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")

View File

@@ -13,6 +13,7 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -41,6 +42,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -72,6 +74,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -99,6 +102,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -129,6 +133,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -157,6 +162,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -186,6 +192,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -218,6 +225,7 @@
"width": "200px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -246,6 +254,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -276,6 +285,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -305,6 +315,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -333,6 +344,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -363,6 +375,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -392,6 +405,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -419,6 +433,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -449,6 +464,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -478,6 +494,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -507,6 +524,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -535,6 +553,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -566,6 +585,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -597,6 +617,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -626,65 +647,7 @@
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "price_list_rate",
"fieldname": "discount_percentage",
"fieldtype": "Percent",
"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": "Discount on Price List Rate (%)",
"length": 0,
"no_copy": 0,
"oldfieldname": "adj_rate",
"oldfieldtype": "Float",
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_19",
"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,
@@ -716,6 +679,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -746,12 +710,13 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.margin_type && doc.price_list_rate",
"fieldname": "total_margin",
"depends_on": "eval:doc.margin_type && doc.price_list_rate && doc.margin_rate_or_amount",
"fieldname": "rate_with_margin",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -760,7 +725,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Margin",
"label": "Rate With Margin",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -776,6 +741,69 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_19",
"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": "price_list_rate",
"fieldname": "discount_percentage",
"fieldtype": "Percent",
"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": "Discount (%) on Price List Rate with Margin",
"length": 0,
"no_copy": 0,
"oldfieldname": "adj_rate",
"oldfieldtype": "Float",
"permlevel": 0,
"precision": "2",
"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,
@@ -803,6 +831,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -834,6 +863,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -865,6 +895,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -892,6 +923,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -923,6 +955,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -954,6 +987,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -983,6 +1017,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1011,6 +1046,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1041,6 +1077,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1071,6 +1108,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1099,6 +1137,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1129,6 +1168,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1159,6 +1199,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1189,6 +1230,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1218,6 +1260,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1246,6 +1289,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1279,6 +1323,7 @@
"width": "120px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1309,6 +1354,7 @@
"width": "120px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1336,6 +1382,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1370,6 +1417,7 @@
"width": "120px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1400,6 +1448,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1431,6 +1480,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1461,6 +1511,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1492,6 +1543,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1521,6 +1573,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1548,6 +1601,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1577,6 +1631,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1607,6 +1662,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1639,6 +1695,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1669,6 +1726,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1699,6 +1757,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -1730,6 +1789,7 @@
"width": "150px"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -1760,6 +1820,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1789,6 +1850,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1820,6 +1882,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1850,6 +1913,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1878,6 +1942,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1909,6 +1974,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1939,6 +2005,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1969,6 +2036,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1998,6 +2066,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2028,6 +2097,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2056,6 +2126,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2094,7 +2165,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-04-19 11:53:26.682964",
"modified": "2017-05-10 17:14:42.681757",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -123,10 +123,10 @@ def round_off_debit_credit(gl_map):
debit_credit_diff = flt(debit_credit_diff, precision)
if gl_map[0]["voucher_type"] == "Journal Entry":
if gl_map[0]["voucher_type"] in ("Journal Entry", "Payment Entry"):
allowance = 5.0 / (10**precision)
else:
allowance = 1
allowance = .5
if abs(debit_credit_diff) >= allowance:
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")

View File

@@ -78,8 +78,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
make_menu_list: function () {
var me = this;
this.page.clear_menu();
// for mobile
this.page.add_menu_item(__("Pay"), function () {
me.validate();
me.update_paid_amount_status(true);
me.create_invoice();
me.make_payment();
}).addClass('visible-xs');
this.page.add_menu_item(__("New Sales Invoice"), function () {
me.save_previous_entry();
me.create_new();
@@ -327,6 +335,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.name = null;
this.load_data(true);
this.setup();
this.set_default_customer()
},
load_data: function (load_doc) {
@@ -360,6 +369,16 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}
},
set_default_customer: function() {
if (this.default_customer && !this.frm.doc.customer) {
this.party_field.$input.val(this.default_customer);
this.frm.doc.customer = this.default_customer;
this.numeric_keypad.show();
this.toggle_list_customer(false)
this.toggle_item_cart(true)
}
},
set_transaction_defaults: function (party) {
var me = this;
this.party = party;
@@ -675,11 +694,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
me.toggle_delete_button();
}
if (this.default_customer && !this.frm.doc.customer) {
this.party_field.$input.val(this.default_customer);
this.frm.doc.customer = this.default_customer;
}
this.party_field.awesomeplete =
new Awesomplete(this.party_field.$input.get(0), {
minChars: 0,
@@ -782,7 +796,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
add_customer: function() {
this.frm.doc.customer = "";
this.update_customer(true)
this.update_customer(true);
this.numeric_keypad.show();
},
update_customer: function (new_customer) {
@@ -860,6 +875,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
this.customer_doc.set_primary_action(__("Save"), function () {
me.make_offline_customer(new_customer);
me.pos_bill.show();
me.list_customers.hide();
});
},

View File

@@ -16,6 +16,21 @@ frappe.query_reports["Accounts Receivable"] = {
"fieldtype": "Link",
"options": "Customer"
},
{
"fieldname":"customer_group",
"label": __("Customer Group"),
"fieldtype": "Link",
"options": "Customer Group"
},
{
"fieldname":"credit_days_based_on",
"label": __("Credit Days Based On"),
"fieldtype": "Select",
"options": "" + NEWLINE + "Fixed Days" + NEWLINE + "Last Day of the Next Month"
},
{
"fieldtype": "Break",
},
{
"fieldname":"report_date",
"label": __("As on Date"),
@@ -29,9 +44,6 @@ frappe.query_reports["Accounts Receivable"] = {
"options": 'Posting Date' + NEWLINE + 'Due Date',
"default": "Posting Date"
},
{
"fieldtype": "Break",
},
{
"fieldname":"range1",
"label": __("Ageing Range 1"),

View File

@@ -71,7 +71,10 @@ class ReceivablePayableReport(object):
"width": 100
})
if args.get("party_type") == "Customer":
columns += [_("Territory") + ":Link/Territory:80"]
columns += [
_("Territory") + ":Link/Territory:80",
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
@@ -139,7 +142,7 @@ class ReceivablePayableReport(object):
# customer territory / supplier type
if args.get("party_type") == "Customer":
row += [self.get_territory(gle.party)]
row += [self.get_territory(gle.party), self.get_customer_group(gle.party)]
if args.get("party_type") == "Supplier":
row += [self.get_supplier_type(gle.party)]
@@ -186,6 +189,9 @@ 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 ""
def get_supplier_type(self, party_name):
return self.get_party_map("Supplier").get(party_name, {}).get("supplier_type") or ""
@@ -193,12 +199,12 @@ class ReceivablePayableReport(object):
def get_party_map(self, party_type):
if not hasattr(self, "party_map"):
if party_type == "Customer":
self.party_map = dict(((r.name, r) for r in frappe.db.sql("""select {0}, {1}, {2} from `tab{3}`"""
.format("name", "customer_name", "territory", party_type), as_dict=True)))
select_fields = "name, customer_name, territory, customer_group"
elif party_type == "Supplier":
self.party_map = dict(((r.name, r) for r in frappe.db.sql("""select {0}, {1}, {2} from `tab{3}`"""
.format("name", "supplier_name", "supplier_type", party_type), as_dict=True)))
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)))
return self.party_map
@@ -251,6 +257,19 @@ class ReceivablePayableReport(object):
conditions.append("party=%s")
values.append(self.filters.get(party_type_field))
if party_type_field=="customer":
if self.filters.get("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}
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"))
return " and ".join(conditions), values
def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):

View File

@@ -16,6 +16,21 @@ frappe.query_reports["Accounts Receivable Summary"] = {
"fieldtype": "Link",
"options": "Customer"
},
{
"fieldname":"customer_group",
"label": __("Customer Group"),
"fieldtype": "Link",
"options": "Customer Group"
},
{
"fieldname":"credit_days_based_on",
"label": __("Credit Days Based On"),
"fieldtype": "Select",
"options": "" + NEWLINE + "Fixed Days" + NEWLINE + "Last Day of the Next Month"
},
{
"fieldtype": "Break",
},
{
"fieldname":"report_date",
"label": __("Date"),
@@ -29,9 +44,6 @@ frappe.query_reports["Accounts Receivable Summary"] = {
"options": 'Posting Date' + NEWLINE + 'Due Date',
"default": "Posting Date"
},
{
"fieldtype": "Break",
},
{
"fieldname":"range1",
"label": __("Ageing Range 1"),

View File

@@ -27,7 +27,10 @@ class AccountsReceivableSummary(ReceivablePayableReport):
str(self.filters.range3) + _("-Above") + ":Currency/currency:100"]
if args.get("party_type") == "Customer":
columns += [_("Territory") + ":Link/Territory:80"]
columns += [
_("Territory") + ":Link/Territory:80",
_("Customer Group") + ":Link/Customer Group:120"
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Type") + ":Link/Supplier Type:80"]
@@ -58,7 +61,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
]
if args.get("party_type") == "Customer":
row += [self.get_territory(party)]
row += [self.get_territory(party), self.get_customer_group(party)]
if args.get("party_type") == "Supplier":
row += [self.get_supplier_type(party)]
@@ -107,7 +110,7 @@ class AccountsReceivableSummary(ReceivablePayableReport):
if args.get("party_type") == "Supplier":
cols += ["supplier_type", "remarks"]
if args.get("party_type") == "Customer":
cols += ["territory", "remarks"]
cols += ["territory", "customer_group", "remarks"]
return self.make_data_dict(cols, voucherwise_data)

View File

@@ -3,6 +3,13 @@
frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Balance Sheet"] = erpnext.financial_statements;
frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check",
"default": 1
});
});

View File

@@ -8,11 +8,20 @@ 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, filters.periodicity, filters.company)
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, only_current_fiscal_year=False)
liability = get_data(filters.company, "Liability", "Credit", period_list, only_current_fiscal_year=False)
equity = get_data(filters.company, "Equity", "Credit", period_list, only_current_fiscal_year=False)
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,
only_current_fiscal_year=False, filters=filters,
accumulated_values=filters.accumulated_values)
equity = get_data(filters.company, "Equity", "Credit", period_list,
only_current_fiscal_year=False, filters=filters,
accumulated_values=filters.accumulated_values)
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
period_list, filters.company)
@@ -43,9 +52,9 @@ def execute(filters=None):
if total_credit:
data.append(total_credit)
columns = get_columns(filters.periodicity, period_list, company=filters.company)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, company=filters.company)
chart = get_chart_data(columns, asset, liability, equity)
chart = get_chart_data(filters, columns, asset, liability, equity)
return columns, data, message, chart
@@ -102,12 +111,13 @@ 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(columns, asset, liability, equity):
def get_chart_data(filters, columns, asset, liability, equity):
x_intervals = ['x'] + [d.get("label") for d in columns[2:]]
asset_data, liability_data, equity_data = [], [], []
@@ -128,9 +138,14 @@ def get_chart_data(columns, asset, liability, equity):
if equity_data:
columns.append(["Equity"] + equity_data)
return {
chart = {
"data": {
'x': 'x',
'columns': columns
}
}
if not filters.accumulated_values:
chart["chart_type"] = "bar"
return chart

View File

@@ -11,7 +11,7 @@ from erpnext.accounts.utils import get_fiscal_year
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.company)
filters.periodicity, filters.accumulated_values, filters.company)
operation_accounts = {
"section_name": "Operations",

View File

@@ -3,10 +3,15 @@
from __future__ import unicode_literals
import frappe
import re
from frappe import _
from frappe.utils import flt, getdate, get_first_day, add_months, add_days, formatdate
from frappe.utils import (flt, getdate, get_first_day, get_last_day, date_diff,
add_months, add_days, formatdate, cint)
from erpnext.accounts.utils import get_fiscal_year
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, company):
def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False,
company=None, reset_period_on_fy_change=True):
"""Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label}
Periodicity can be (Yearly, Quarterly, Monthly)"""
@@ -48,7 +53,8 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, company):
# if a fiscal year ends before a 12 month period
period.to_date = year_end_date
period.to_date_fiscal_year = get_date_fiscal_year(period.to_date, company)
period.to_date_fiscal_year = get_fiscal_year(period.to_date, company=company)[0]
period.from_date_fiscal_year_start_date = get_fiscal_year(period.from_date, company=company)[1]
period_list.append(period)
@@ -58,11 +64,17 @@ def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, company):
# common processing
for opts in period_list:
key = opts["to_date"].strftime("%b_%Y").lower()
if periodicity == "Monthly":
if periodicity == "Monthly" and not accumulated_values:
label = formatdate(opts["to_date"], "MMM YYYY")
else:
label = get_label(periodicity, opts["from_date"], opts["to_date"])
if not accumulated_values:
label = get_label(periodicity, opts["from_date"], opts["to_date"])
else:
if reset_period_on_fy_change:
label = get_label(periodicity, opts.from_date_fiscal_year_start_date, opts["to_date"])
else:
label = get_label(periodicity, period_list[0].from_date, opts["to_date"])
opts.update({
"key": key.replace(" ", "_").replace("-", "_"),
"label": label,
@@ -139,16 +151,13 @@ def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accum
if entry.posting_date <= period.to_date:
if (accumulated_values or entry.posting_date >= period.from_date) and \
(not ignore_accumulated_values_for_fy or entry.fiscal_year == period.to_date_fiscal_year):
(not ignore_accumulated_values_for_fy or
entry.fiscal_year == period.to_date_fiscal_year):
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
if entry.posting_date < period_list[0].year_start_date:
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
def get_date_fiscal_year(date, company):
from erpnext.accounts.utils import get_fiscal_year
return get_fiscal_year(date, company=company)[0]
def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values):
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
@@ -269,6 +278,9 @@ def sort_root_accounts(roots):
"""Sort root types as Asset, Liability, Equity, Income, Expense"""
def compare_roots(a, b):
if re.split('\W+', a.value)[0].isdigit():
# if chart of accounts is numbered, then sort by number
return cmp(a.value, b.value)
if a.report_type != b.report_type and a.report_type == "Balance Sheet":
return -1
if a.root_type != b.root_type and a.root_type == "Asset":

View File

@@ -5,7 +5,15 @@
</div>
{% } %}
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
<h4 class="text-center">{%= (filters.party || filters.account) && ((filters.party || filters.account) + ", ") || "" %} {%= filters.company %}</h4>
<h4 class="text-center">
{% if (filters.party_name) { %}
{%= filters.party_name %}
{% } else if (filters.party) { %}
{%= filters.party %}
{% } else if (filters.account) { %}
{%= filters.account %}
{% } %}
</h4>
<h5 class="text-center">
{%= dateutil.str_to_user(filters.from_date) %}
{%= __("to") %}

View File

@@ -74,8 +74,27 @@ frappe.query_reports["General Ledger"] = {
frappe.throw(__("Please select Party Type first"));
}
return party_type;
},
change: function() {
var party_type = frappe.query_report_filters_by_name.party_type.get_value();
var party = frappe.query_report_filters_by_name.party.get_value();
if(!party_type || !party) {
frappe.query_report_filters_by_name.party_name.set_value("");
return;
}
var fieldname = party_type.toLowerCase() + "_name";
frappe.db.get_value(party_type, party, fieldname, function(value) {
frappe.query_report_filters_by_name.party_name.set_value(value[fieldname]);
});
}
},
{
"fieldname":"party_name",
"label": __("Party Name"),
"fieldtype": "Data",
"hidden": 1
},
{
"fieldname":"group_by_voucher",
"label": __("Group by Voucher"),

View File

@@ -9,12 +9,15 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity, filters.company)
filters.periodicity, filters.accumulated_values, filters.company)
income = get_data(filters.company, "Income", "Credit", period_list, filters = filters,
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
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, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
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)

View File

@@ -20,7 +20,7 @@ def execute(filters=None):
invoice_expense_map, invoice_tax_map = get_invoice_tax_map(invoice_list,
invoice_expense_map, expense_accounts)
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
supplier_details = get_supplier_deatils(invoice_list)
supplier_details = get_supplier_details(invoice_list)
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
@@ -205,7 +205,7 @@ def get_account_details(invoice_list):
return account_map
def get_supplier_deatils(invoice_list):
def get_supplier_details(invoice_list):
supplier_details = {}
suppliers = list(set([inv.supplier for inv in invoice_list]))
for supp in frappe.db.sql("""select name, supplier_type from `tabSupplier`

View File

@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
import frappe, erpnext
from frappe import _
from frappe.utils import flt, getdate, formatdate, cstr
from erpnext.accounts.report.financial_statements \
@@ -53,6 +53,7 @@ def validate_filters(filters):
def get_data(filters):
accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
company_currency = erpnext.get_company_currency(filters.company)
if not accounts:
return None
@@ -69,10 +70,10 @@ def get_data(filters):
opening_balances = get_opening_balances(filters)
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters, company_currency)
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row, parent_children_map)
data = prepare_data(accounts, filters, total_row, parent_children_map, company_currency)
data = filter_out_zero_value_rows(data, parent_children_map,
show_zero_values=filters.get("show_zero_values"))
@@ -119,7 +120,7 @@ def get_rootwise_opening_balances(filters, report_type):
return opening
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters, company_currency):
init = {
"opening_debit": 0.0,
"opening_credit": 0.0,
@@ -137,7 +138,8 @@ def calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
"credit": 0.0,
"parent_account": None,
"indent": 0,
"has_value": True
"has_value": True,
"currency": company_currency
}
for d in accounts:
@@ -164,9 +166,8 @@ def accumulate_values_into_parents(accounts, accounts_by_name):
for key in value_fields:
accounts_by_name[d.parent_account][key] += d[key]
def prepare_data(accounts, filters, total_row, parent_children_map):
def prepare_data(accounts, filters, total_row, parent_children_map, company_currency):
data = []
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
for d in accounts:
has_value = False

View File

@@ -4,14 +4,13 @@
from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe.utils import nowdate, cstr, flt, cint, now, getdate
from frappe import throw, _
from frappe.utils import formatdate
from frappe.utils import formatdate, get_number_format_info
# imported to enable erpnext.accounts.utils.get_account_currency
from erpnext.accounts.doctype.account.account import get_account_currency
import frappe.defaults
from erpnext.accounts.report.financial_statements import sort_root_accounts
class FiscalYearError(frappe.ValidationError): pass
@@ -537,15 +536,14 @@ def get_stock_and_account_difference(account_list=None, posting_date=None):
return difference
def get_currency_precision(currency=None):
if not currency:
currency = frappe.db.get_value("Company",
frappe.db.get_default("Company"), "default_currency", cache=True)
currency_format = frappe.db.get_value("Currency", currency, "number_format", cache=True)
from frappe.utils import get_number_format_info
return get_number_format_info(currency_format)[2]
def get_currency_precision():
precision = cint(frappe.db.get_default("currency_precision"))
if not precision:
number_format = frappe.db.get_default("number_format") or "#,###.##"
precision = get_number_format_info(number_format)[2]
return precision
def get_stock_rbnb_difference(posting_date, company):
stock_items = frappe.db.sql_list("""select distinct item_code
from `tabStock Ledger Entry` where company=%s""", company)
@@ -653,6 +651,8 @@ def get_companies():
@frappe.whitelist()
def get_children():
from erpnext.accounts.report.financial_statements import sort_root_accounts
args = frappe.local.form_dict
doctype, company = args['doctype'], args['company']
fieldname = frappe.db.escape(doctype.lower().replace(' ','_'))

View File

@@ -153,30 +153,37 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
},
add_from_mappers: function() {
cur_frm.add_custom_button(__('Material Request'),
var me = this;
this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request",
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
company: cur_frm.doc.company
}
})
}, __("Add items from"));
cur_frm.add_custom_button(__('Supplier Quotation'),
this.frm.add_custom_button(__('Supplier Quotation'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
source_doctype: "Supplier Quotation",
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
docstatus: 1,
status: ["!=", "Stopped"],
company: cur_frm.doc.company
}
})
}, __("Add items from"));

View File

@@ -59,7 +59,8 @@ class PurchaseOrder(BuyingController):
},
"Supplier Quotation Item": {
"ref_dn_field": "supplier_quotation_item",
"compare_fields": [["rate", "="], ["project", "="], ["item_code", "="]],
"compare_fields": [["rate", "="], ["project", "="], ["item_code", "="],
["uom", "="], ["conversion_factor", "="]],
"is_child_table": True
}
})

View File

@@ -3,6 +3,10 @@ from frappe import _
def get_data():
return {
'fieldname': 'purchase_order',
'non_standard_fieldnames': {
'Journal Entry': 'reference_name',
'Payment Entry': 'reference_name'
},
'internal_links': {
'Material Request': ['items', 'material_request'],
'Supplier Quotation': ['items', 'supplier_quotation'],
@@ -13,6 +17,10 @@ def get_data():
'label': _('Related'),
'items': ['Purchase Receipt', 'Purchase Invoice']
},
{
'label': _('Payment'),
'items': ['Payment Entry', 'Journal Entry']
},
{
'label': _('Reference'),
'items': ['Material Request', 'Supplier Quotation', 'Project']
@@ -20,6 +28,6 @@ def get_data():
{
'label': _('Sub-contracting'),
'items': ['Stock Entry']
},
}
]
}

View File

@@ -800,7 +800,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "9",
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "100px",
@@ -1659,7 +1659,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-04-18 18:49:08.604055",
"modified": "2017-04-25 18:49:08.604055",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@@ -48,7 +48,7 @@ frappe.ui.form.on("Request for Quotation",{
});
});
}
},
make_suppplier_quotation: function(frm) {
@@ -124,24 +124,28 @@ frappe.ui.form.on("Request for Quotation Supplier",{
erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
var me = this;
this._super();
if (this.frm.doc.docstatus===0) {
cur_frm.add_custom_button(__('Material Request'),
this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
source_doctype: "Material Request",
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
company: cur_frm.doc.company
per_ordered: ["<", 99.99]
}
})
}, __("Get items from"));
// Get items from open Material Requests based on supplier
cur_frm.add_custom_button(__('Possible Supplier'), function() {
this.frm.add_custom_button(__('Possible Supplier'), function() {
// Create a dialog window for the user to pick their supplier
var d = new frappe.ui.Dialog({
title: __('Select Possible Supplier'),
@@ -150,32 +154,35 @@ erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.e
{fieldname: 'ok_button', fieldtype:'Button', label:'Get Items from Material Requests'},
]
});
// On the user clicking the ok button
d.fields_dict.ok_button.input.onclick = function() {
var btn = d.fields_dict.ok_button.input;
var v = d.get_values();
if(v) {
$(btn).set_working();
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
source_name: v.supplier,
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
company: cur_frm.doc.company
per_ordered: ["<", 99.99]
}
});
$(btn).done_working();
d.hide();
}
}
}
d.show();
}, __("Get items from"));
}
},

View File

@@ -15,6 +15,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -45,6 +46,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -76,6 +78,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -106,6 +109,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -136,6 +140,37 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "tax_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": "Tax ID",
"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,
@@ -165,6 +200,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -193,6 +229,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -224,6 +261,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -254,6 +292,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -284,6 +323,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -313,6 +353,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -342,6 +383,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -370,6 +412,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -399,6 +442,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -428,6 +472,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -458,6 +503,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -487,6 +533,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -518,6 +565,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -546,6 +594,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -574,6 +623,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -602,6 +652,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -631,12 +682,13 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "Mention if non-standard receivable account",
"description": "Mention if non-standard payable account",
"fieldname": "accounts",
"fieldtype": "Table",
"hidden": 0,
@@ -662,6 +714,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -692,6 +745,7 @@
"width": "50%"
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -722,6 +776,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -753,6 +808,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -794,7 +850,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-14 17:04:17.785461",
"modified": "2017-05-17 12:21:21.218428",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",

View File

@@ -14,6 +14,7 @@ frappe.ui.form.on('Suppier Quotation', {
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
var me = this;
this._super();
if (this.frm.doc.docstatus === 1) {
cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
@@ -24,18 +25,21 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
}
else if (this.frm.doc.docstatus===0) {
cur_frm.add_custom_button(__('Material Request'),
this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation",
source_doctype: "Material Request",
target: me.frm,
setters: {
company: me.frm.doc.company
},
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
company: cur_frm.doc.company
per_ordered: ["<", 99.99]
}
})
}, __("Get items from"));

View File

@@ -35,11 +35,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
item_key: "supplier",
parent_field: "parent_supplier_type",
formatter: function(item) {
// return repl('<a href="#Report/stock-invoices/customer=%(enc_value)s">%(value)s</a>', {
// value: item.name,
// enc_value: encodeURIComponent(item.name)
// });
return item.name;
return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name;
}
},
"Supplier": {
@@ -47,7 +43,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({
show: false,
item_key: "supplier",
formatter: function(item) {
return item.name;
return item.supplier_name ? item.supplier_name + " (" + item.name + ")" : item.name;
}
},
"Item Group": {

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cstr, cint
from frappe import _
import json
from erpnext.stock.doctype.item.item import get_last_purchase_details
from erpnext.stock.doctype.item.item import validate_end_of_life
@@ -63,7 +64,7 @@ def validate_for_items(doc):
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
# validate stock item
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.delivered_by_supplier:
if item.is_stock_item==1 and d.qty and not d.warehouse and not d.get("delivered_by_supplier"):
frappe.throw(_("Warehouse is mandatory for stock Item {0} in row {1}").format(d.item_code, d.idx))
items.append(cstr(d.item_code))
@@ -78,3 +79,25 @@ def check_for_closed_status(doctype, docname):
if status == "Closed":
frappe.throw(_("{0} {1} status is {2}").format(doctype, docname, status), frappe.InvalidStatusError)
@frappe.whitelist()
def get_linked_material_requests(items):
items = json.loads(items)
mr_list = []
for item in items:
material_request = frappe.db.sql("""SELECT distinct mr.name AS mr_name,
(mr_item.qty - mr_item.ordered_qty) AS qty,
mr_item.item_code AS item_code,
mr_item.name AS mr_item
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
WHERE mr.name = mr_item.parent
AND mr_item.item_code = %(item)s
AND mr.material_request_type = 'Purchase'
AND mr.per_ordered < 99.99
AND mr.docstatus = 1
AND mr.status != 'Stopped'
ORDER BY mr_item.item_code ASC""",{"item": item}, as_dict=1)
if material_request:
mr_list.append(material_request)
return mr_list

View File

@@ -159,6 +159,11 @@ def get_data():
"is_query_report": True,
"doctype": "Journal Entry"
},
{
"type": "doctype",
"name": "Bank Guarantee",
"doctype": "Bank Guarantee"
},
]
},
{

View File

@@ -68,6 +68,18 @@ def get_data():
"name": "Inactive Customers",
"doctype": "Sales Order"
},
{
"type": "report",
"is_query_report": True,
"name": "Campaign Efficiency",
"doctype": "Lead"
},
{
"type": "report",
"is_query_report": True,
"name": "Lead Owner Efficiency",
"doctype": "Lead"
}
]
},
{

View File

@@ -18,10 +18,6 @@ def get_data():
"type": "doctype",
"name": "Student Log"
},
{
"type": "doctype",
"name": "Student Batch"
},
{
"type": "doctype",
"name": "Student Group"
@@ -58,10 +54,6 @@ def get_data():
{
"type": "doctype",
"name": "Program Enrollment Tool"
},
{
"type": "doctype",
"name": "Student Batch Creation Tool"
}
]
},

View File

@@ -42,10 +42,8 @@ def make_variant_based_on_manufacturer(template, manufacturer, manufacturer_part
copy_attributes_to_variant(template, variant)
variant.append("manufacturers", {
"manufacturer": manufacturer,
"manufacturer_part_no": manufacturer_part_no
})
variant.manufacturer = manufacturer
variant.manufacturer_part_no = manufacturer_part_no
variant.item_code = append_number_if_name_exists('Item', template.name)

View File

@@ -222,19 +222,21 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
"_txt": txt.replace('%', '')
})
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select `tabDelivery Note`.name, `tabDelivery Note`.customer_name
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict):
return frappe.db.sql("""
select `tabDelivery Note`.name, `tabDelivery Note`.customer, `tabDelivery Note`.posting_date
from `tabDelivery Note`
where `tabDelivery Note`.`%(key)s` like %(txt)s and
`tabDelivery Note`.docstatus = 1 and status not in ("Stopped", "Closed") %(fcond)s
`tabDelivery Note`.docstatus = 1 and `tabDelivery Note`.is_return = 0
and status not in ("Stopped", "Closed") %(fcond)s
and (`tabDelivery Note`.per_billed < 100 or `tabDelivery Note`.grand_total = 0)
%(mcond)s order by `tabDelivery Note`.`%(key)s` asc
limit %(start)s, %(page_len)s""" % {
"key": searchfield,
"fcond": get_filters_cond(doctype, filters, []),
"mcond": get_match_cond(doctype),
"start": "%(start)s", "page_len": "%(page_len)s", "txt": "%(txt)s"
}, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) })
""" % {
"key": searchfield,
"fcond": get_filters_cond(doctype, filters, []),
"mcond": get_match_cond(doctype),
"txt": "%(txt)s"
}, { "txt": ("%%%s%%" % txt) }, as_dict=as_dict)
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
cond = ""
@@ -360,7 +362,8 @@ def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
sub_query = """ select round(`tabBin`.actual_qty, 2) from `tabBin`
where `tabBin`.warehouse = `tabWarehouse`.name
{bin_conditions} """.format(
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"), bin_conditions))
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),
bin_conditions, ignore_permissions=True))
response = frappe.db.sql("""select `tabWarehouse`.name,
CONCAT_WS(" : ", "Actual Qty", ifnull( ({sub_query}), 0) ) as actual_qty

View File

@@ -53,8 +53,8 @@ def validate_returned_items(doc):
valid_items = frappe._dict()
select_fields = "item_code, qty, parenttype" if doc.doctype=="Purchase Invoice" \
else "item_code, qty, serial_no, batch_no, parenttype"
select_fields = "item_code, qty, rate, parenttype" if doc.doctype=="Purchase Invoice" \
else "item_code, qty, rate, serial_no, batch_no, parenttype"
if doc.doctype in ['Purchase Invoice', 'Purchase Receipt']:
select_fields += ",rejected_qty, received_qty"
@@ -82,10 +82,15 @@ def validate_returned_items(doc):
else:
ref = valid_items.get(d.item_code, frappe._dict())
validate_quantity(doc, d, ref, valid_items, already_returned_items)
if ref.batch_no and d.batch_no not in ref.batch_no:
if ref.rate and doc.doctype in ("Delivery Note", "Sales Invoice") and flt(d.rate) > ref.rate:
frappe.throw(_("Row # {0}: Rate cannot be greater than the rate used in {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
elif ref.batch_no and d.batch_no not in ref.batch_no:
frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
.format(d.idx, doc.doctype, doc.return_against))
elif ref.serial_no:
if not d.serial_no:
frappe.throw(_("Row # {0}: Serial No is mandatory").format(d.idx))
@@ -131,6 +136,7 @@ def get_ref_item_dict(valid_items, ref_item_row):
valid_items.setdefault(ref_item_row.item_code, frappe._dict({
"qty": 0,
"rate": 0,
"rejected_qty": 0,
"received_qty": 0,
"serial_no": [],
@@ -138,6 +144,7 @@ def get_ref_item_dict(valid_items, ref_item_row):
}))
item_dict = valid_items[ref_item_row.item_code]
item_dict["qty"] += ref_item_row.qty
item_dict["rate"] = ref_item_row.get("rate", 0)
if ref_item_row.parenttype in ['Purchase Invoice', 'Purchase Receipt']:
item_dict["received_qty"] += ref_item_row.received_qty

View File

@@ -170,7 +170,7 @@ class SellingController(StockController):
def validate_selling_price(self):
def throw_message(item_name, rate, ref_rate_field):
frappe.throw(_("""Selling price for item {0} is lower than its {1}. Selling price should be atleast {2}""")
frappe.throw(_("""Selling rate for item {0} is lower than its {1}. Selling rate should be atleast {2}""")
.format(item_name, ref_rate_field, rate))
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
@@ -178,18 +178,19 @@ class SellingController(StockController):
for it in self.get("items"):
last_purchase_rate, is_stock_item = frappe.db.get_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
if flt(it.base_rate) < flt(last_purchase_rate):
throw_message(it.item_name, last_purchase_rate, "last purchase rate")
last_purchase_rate_in_sales_uom = last_purchase_rate / (it.conversion_factor or 1)
if flt(it.base_rate) < flt(last_purchase_rate_in_sales_uom):
throw_message(it.item_name, last_purchase_rate_in_sales_uom, "last purchase rate")
last_valuation_rate = frappe.db.sql("""
SELECT valuation_rate FROM `tabStock Ledger Entry` WHERE item_code = %s
AND warehouse = %s AND valuation_rate > 0
ORDER BY posting_date DESC, posting_time DESC, name DESC LIMIT 1
""", (it.item_code, it.warehouse))
if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate):
throw_message(it.name, last_valuation_rate, "valuation rate")
if last_valuation_rate:
last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] / (it.conversion_factor or 1)
if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate_in_sales_uom):
throw_message(it.name, last_valuation_rate_in_sales_uom, "valuation rate")
def get_item_list(self):

View File

@@ -19,7 +19,7 @@ status_map = {
["Converted", "has_customer"],
],
"Opportunity": [
["Quotation", "has_quotation"],
["Quotation", "has_active_quotation"],
["Converted", "has_ordered_quotation"],
["Lost", "eval:self.status=='Lost'"],
["Lost", "has_lost_quotation"],
@@ -46,8 +46,8 @@ status_map = {
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1 and self.is_return==0"],
["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"],
["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -56,8 +56,8 @@ status_map = {
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1 and self.is_return==0"],
["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"],
["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -119,7 +119,8 @@ class StatusUpdater(Document):
self.status = s[0]
break
elif s[1].startswith("eval:"):
if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, "nowdate": nowdate }):
if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate,
"nowdate": nowdate, "get_value": frappe.db.get_value }):
self.status = s[0]
break
elif getattr(self, s[1])():

View File

@@ -59,10 +59,10 @@ class calculate_taxes_and_totals(object):
(1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))
if item.doctype in ['Quotation Item', 'Sales Order Item', 'Delivery Note Item', 'Sales Invoice Item']:
item.total_margin = self.calculate_margin(item)
item.rate_with_margin = self.calculate_margin(item)
item.rate = flt(item.total_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))\
if item.total_margin > 0 else item.rate
item.rate = flt(item.rate_with_margin * (1.0 - (item.discount_percentage / 100.0)), item.precision("rate"))\
if item.rate_with_margin > 0 else item.rate
item.net_rate = item.rate
item.amount = flt(item.rate * item.qty, item.precision("amount"))
@@ -465,6 +465,8 @@ class calculate_taxes_and_totals(object):
payment.base_amount = flt(payment.amount * self.doc.conversion_rate)
paid_amount += payment.amount
base_paid_amount += payment.base_amount
elif not self.doc.is_return:
self.doc.set('payments', [])
self.doc.paid_amount = flt(paid_amount, self.doc.precision("paid_amount"))
self.doc.base_paid_amount = flt(base_paid_amount, self.doc.precision("base_paid_amount"))
@@ -487,7 +489,7 @@ class calculate_taxes_and_totals(object):
self.doc.precision("base_write_off_amount"))
def calculate_margin(self, item):
total_margin = 0.0
rate_with_margin = 0.0
if item.price_list_rate:
if item.pricing_rule and not self.doc.ignore_pricing_rule:
pricing_rule = frappe.get_doc('Pricing Rule', item.pricing_rule)
@@ -496,6 +498,6 @@ class calculate_taxes_and_totals(object):
if item.margin_type and item.margin_rate_or_amount:
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
total_margin = flt(item.price_list_rate) + flt(margin_value)
rate_with_margin = flt(item.price_list_rate) + flt(margin_value)
return total_margin
return rate_with_margin

View File

@@ -0,0 +1,73 @@
from __future__ import unicode_literals
import unittest
import frappe
import random, json
import frappe.utils
from frappe.utils import nowdate
from frappe.model import mapper
from frappe.test_runner import make_test_records
class TestMapper(unittest.TestCase):
def test_map_docs(self):
'''Test mapping of multiple source docs on a single target doc'''
make_test_records("Item")
items = frappe.get_all("Item", fields = ["name", "item_code"], filters = {'is_sales_item': 1, 'has_variants': 0})
customers = frappe.get_all("Customer")
if items and customers:
# Make source docs (quotations) and a target doc (sales order)
customer = random.choice(customers).name
qtn1, item_list_1 = self.make_quotation(items, customer)
qtn2, item_list_2 = self.make_quotation(items, customer)
so, item_list_3 = self.make_sales_order()
# Map source docs to target with corresponding mapper method
method = "erpnext.selling.doctype.quotation.quotation.make_sales_order"
updated_so = mapper.map_docs(method, json.dumps([qtn1.name, qtn2.name]), so)
# Assert that all inserted items are present in updated sales order
src_items = item_list_1 + item_list_2 + item_list_3
self.assertEqual(set([d.item_code for d in src_items]),
set([d.item_code for d in updated_so.items]))
def get_random_items(self, items, limit):
'''Get a number of random items from a list of given items'''
random_items = []
for i in range(0, limit):
random_items.append(random.choice(items))
return random_items
def make_quotation(self, items, customer):
item_list = self.get_random_items(items, 3)
qtn = frappe.get_doc({
"doctype": "Quotation",
"quotation_to": "Customer",
"customer": customer,
"order_type": "Sales"
})
for item in item_list:
qtn.append("items", {"qty": "2", "item_code": item.item_code})
qtn.submit()
return qtn, item_list
def make_sales_order(self):
item = frappe.get_doc({
"base_amount": 1000.0,
"base_rate": 100.0,
"description": "CPU",
"doctype": "Sales Order Item",
"item_code": "_Test Item Home Desktop 100",
"item_name": "CPU",
"parentfield": "items",
"qty": 10.0,
"rate": 100.0,
"warehouse": "_Test Warehouse - _TC",
"stock_uom": "_Test UOM",
"conversion_factor": 1.0,
"uom": "_Test UOM"
})
so = frappe.get_doc(frappe.get_test_records('Sales Order')[0])
so.insert(ignore_permissions=True)
return so, [item]

View File

@@ -84,20 +84,31 @@ class Opportunity(TransactionBase):
def on_trash(self):
self.delete_events()
def has_quotation(self):
return frappe.db.get_value("Quotation Item", {"prevdoc_docname": self.name, "docstatus": 1})
def has_active_quotation(self):
return frappe.db.sql("""
select q.name
from `tabQuotation` q, `tabQuotation Item` qi
where q.name = qi.parent and q.docstatus=1 and qi.prevdoc_docname =%s
and q.status not in ('Lost', 'Closed')""", self.name)
def has_ordered_quotation(self):
return frappe.db.sql("""select q.name from `tabQuotation` q, `tabQuotation Item` qi
where q.name = qi.parent and q.docstatus=1 and qi.prevdoc_docname =%s and q.status = 'Ordered'""", self.name)
return frappe.db.sql("""
select q.name
from `tabQuotation` q, `tabQuotation Item` qi
where q.name = qi.parent and q.docstatus=1 and qi.prevdoc_docname =%s
and q.status = 'Ordered'""", self.name)
def has_lost_quotation(self):
return frappe.db.sql("""
lost_quotation = frappe.db.sql("""
select q.name
from `tabQuotation` q, `tabQuotation Item` qi
where q.name = qi.parent and q.docstatus=1
and qi.prevdoc_docname =%s and q.status = 'Lost'
""", self.name)
if lost_quotation:
if self.has_active_quotation():
return False
return True
def validate_cust_name(self):
if self.customer:

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Campaign Efficiency"] = {
"filters": [
{
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_start_date"),
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date"),
}
]
};

View File

@@ -0,0 +1,30 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-04-17 00:20:27.248275",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2017-04-17 00:20:27.248275",
"modified_by": "Administrator",
"module": "CRM",
"name": "Campaign Efficiency",
"owner": "Administrator",
"ref_doctype": "Lead",
"report_name": "Campaign Efficiency",
"report_type": "Script Report",
"roles": [
{
"role": "Sales User"
},
{
"role": "Sales Manager"
},
{
"role": "System Manager"
}
]
}

View File

@@ -0,0 +1,89 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
def execute(filters=None):
columns, data = [], []
columns=get_columns()
data=get_lead_data(filters, "Campaign Name")
return columns, data
def get_columns():
return [
_("Campaign Name") + ":data:130",
_("Lead Count") + ":Int:80",
_("Opp Count") + ":Int:80",
_("Quot Count") + ":Int:80",
_("Order Count") + ":Int:100",
_("Order Value") + ":Float:100",
_("Opp/Lead %") + ":Float:100",
_("Quot/Lead %") + ":Float:100",
_("Order/Quot %") + ":Float:100"
]
def get_lead_data(filters, based_on):
based_on_field = frappe.scrub(based_on)
conditions = get_filter_conditions(filters)
lead_details = frappe.db.sql("""
select {based_on_field}, name
from `tabLead`
where {based_on_field} is not null and {based_on_field} != '' {conditions}
""".format(based_on_field=based_on_field, conditions=conditions), filters, as_dict=1)
lead_map = frappe._dict()
for d in lead_details:
lead_map.setdefault(d.get(based_on_field), []).append(d.name)
data = []
for based_on_value, leads in lead_map.items():
row = {
based_on: based_on_value,
"Lead Count": len(leads)
}
row["Quot Count"]= get_lead_quotation_count(leads)
row["Opp Count"] = get_lead_opp_count(leads)
row["Order Count"] = get_quotation_ordered_count(leads)
row["Order Value"] = get_order_amount(leads)
row["Opp/Lead %"] = row["Opp Count"] / row["Lead Count"] * 100
row["Quot/Lead %"] = row["Quot Count"] / row["Lead Count"] * 100
row["Order/Quot %"] = row["Order Count"] / (row["Quot Count"] or 1) * 100
data.append(row)
return data
def get_filter_conditions(filters):
conditions=""
if filters.from_date:
conditions += " and date(creation) >= %(from_date)s"
if filters.to_date:
conditions += " and date(creation) <= %(to_date)s"
return conditions
def get_lead_quotation_count(leads):
return frappe.db.sql("""select count(name) from `tabQuotation`
where lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
def get_lead_opp_count(leads):
return frappe.db.sql("""select count(name) from `tabOpportunity`
where lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
def get_quotation_ordered_count(leads):
return frappe.db.sql("""select count(name)
from `tabQuotation` where status = 'Ordered'
and lead in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
def get_order_amount(leads):
return frappe.db.sql("""select sum(base_net_amount)
from `tabSales Order Item`
where prevdoc_docname in (
select name from `tabQuotation` where status = 'Ordered'
and lead in (%s)
)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]

View File

@@ -0,0 +1,17 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Lead Owner Efficiency"] = {
"filters": [
{
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_start_date"),
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date"),
}
]};

View File

@@ -0,0 +1,30 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2017-04-17 00:39:39.885905",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2017-04-17 00:45:10.139004",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Owner Efficiency",
"owner": "Administrator",
"ref_doctype": "Lead",
"report_name": "Lead Owner Efficiency",
"report_type": "Script Report",
"roles": [
{
"role": "Sales User"
},
{
"role": "Sales Manager"
},
{
"role": "System Manager"
}
]
}

View File

@@ -0,0 +1,26 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from erpnext.crm.report.campaign_efficiency.campaign_efficiency import get_lead_data
def execute(filters=None):
columns, data = [], []
columns=get_columns()
data=get_lead_data(filters, "Lead Owner")
return columns, data
def get_columns():
return [
_("Lead Owner") + ":Data:130",
_("Lead Count") + ":Int:80",
_("Opp Count") + ":Int:80",
_("Quot Count") + ":Int:80",
_("Order Count") + ":Int:100",
_("Order Value") + ":Float:100",
_("Opp/Lead %") + ":Float:100",
_("Quot/Lead %") + ":Float:100",
_("Order/Quot %") + ":Float:100"
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,9 @@
A Bank Guarantee is a guarantee from a lending institution such as a bank ensuring the liabilities of a debtor will be met. In other words, if the debtor fails to settle a debt, the bank covers it. A Bank Guarantee enables the customer, or debtor, to acquire goods, buy equipment or draw down loans, and thereby expand business activity.
A client may ask you to provide a Bank Guarantee from a third party such as a bank. This guarantee is for a specified amount, which is usually a percentage of the total value of the contract. The Bank Guarantee is valid for a specified duration after which it expires and must be returned to you by the client.
This document allows you to track Bank Guarantees given to clients. You can set Email Alerts as the Bank Guarantee expiry date approaches to remind yourself to get the Bank Guarantee back from your client.
<img class="screenshot" alt="Bank Guarantee" src="{{docs_base_url}}/assets/img/accounts/bank-guarantee.png">
{next}

View File

@@ -10,6 +10,7 @@ multi-currency-accounting
advance-payment-entry
payment-request
credit-limit
bank-guarantee
accounting-reports
accounting-entries
managing-fixed-assets

View File

@@ -1,29 +1,35 @@
Taxes selected in the Tax and Other Charges in transactions are applied on all the items. If you need different taxes applied on items selected in the same transaction, you should setup you item and tax master as explained in the steps below.
In the sales and purchase transactions, you can apply taxes and other charges on the items. For the ease of applying taxes, you can fetch values from the [Sales Taxes and Charges master](/contents//setting-up/setting-up-taxes). Taxes and charges are applied equally on all the items. For example, if tax GST 16% is added in the tax table, then it will be applied on all the items. However, if you need to have different tax rate applied on some of the items, following is how you should setup Items and Sales Taxes and Other Charges master in your ERPNext account.
Let's assume that we are creating a Sales Order. We have Sales Taxes and Charges master for GST 16%. Out of all the Sales Items, on one item, only 12% GST will be applied, while one more item is exempted from the tax.
####Step 1: Mention Tax Applicable in the Item master
Item master has tax table where you can list taxes which will be applied on it.
Items on which differential tax rate is applied, you should mention tax rate for that item in the Item master itself. Item master has tax table where you can list taxes which will be applied on it.
![Item wise Tax]({{docs_base_url}}/assets/old_images/erpnext/item-wise-tax.png)
> Tax rate mentioned in the item master gets preference over tax rate entered in the transactions.
Tax rate mentioned in the item master gets preference over tax rate entered in the transactions.
Here is the example of Item on which 12% GST is applied only.
For example, if you provide tax rate for VAT as 10% for item ABC, where for same VAT ledger 12% rate is entered in the Sales Order/Invoice, for item ABC, tax rate applied would be 10%, as mentioned in the item master.
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/item-wise-tax.png">
For the item which is exempted from GST totally, mention 0% as tax rate in the Item master.
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/exempted-item.png">
####Step 2: Setup Taxes and Other Charges
In Taxes and Other Charges master, you should select all the applicable taxes which could be applicable on item.
In Sales Taxes and Other Charges master, select GST 16% account and mention Tax Rate as 16. This tax rate will be applied on all the Items selected in the Sales Order, unless specific Tax Rate is defined in the Item master.
For example, if few items has VAT 5 applied on them, other has Service Tax applied, and some other has Excise Duty applicable, then you tax master should have all these taxes selected.
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/tax-master.png">
![item wise tax master]({{docs_base_url}}/assets/old_images/erpnext/item-wise-tax-master.png)
<div class="well">If you want to have tax rate always applied from the Item master, then you should update Rate for the tax account as zero in the Taxes and Charges master.</div>
####Step 3: Set Tax Rate as Zero in Taxes and Charges Template
####Step 3: Tax Calculation in transaction
In the Taxes and Other Charges master, tax rate will be updated as ZERO. It means, tax rate applicable on items will be pulled from the respective Item master. While for other items, 0% tax will be applied, means no other taxes will be applied on that item.
In the Sales Order, we have selected many Items. For the items mentioned in blue, tax rate is applied based on tax rate mentioned in the taxes table. For the items highlited in red, tax rate has fetched for them from the respective item master.
Based on the above setting, you will have taxes applied on items as mentioned in the respective item master. Check following for an instance.
<img class="screenshot" alt="Opening Account" src="{{docs_base_url}}/assets/img/accounts/tax-calulation.png">
![item wise tax calculation]({{docs_base_url}}/assets/old_images/erpnext/item-wise-tax-calc.png)
Please note that item's tax rate will be pulled from the item master only if you have update same tax account (GST 16% in this case) in both Item master and tax master.
{next}

View File

@@ -64,7 +64,7 @@ On submission of the invoice, the "Fixed Asset Account" will be debited and paya
## Sell an Asset
To sale an asset, open the asset record and create a Sales Invoice by clicking on "Sale Asset". On submission of the Sales Invoice, following entries will take place:
To sell an asset, open the asset record and create a Sales Invoice by clicking on "Sell Asset". On submission of the Sales Invoice, following entries will take place:
- "Receivable Account" (Debtors) will be debited by the sales amount.
- "Fixed Asset Account" will be credited by the purchase amount of asset.

View File

@@ -1,6 +1,6 @@
People who assist you in getting business are termed as Sales Partners. Sales Partners can be represented by different names in ERPNext. You can call them Channel Partner, Distributor, Dealer, Agent, Retailer, Implementation Partner, Reseller etc.
For each Sales Partner, you can define commission offer to them. When Sales Partner is selected in transactions, there commission is calculated over Net Total of Sales Order/Invoice or Delivery Note.
For each Sales Partner, you can define commission offer to them. When Sales Partner is selected in transactions, their commission is calculated over Net Total of Sales Order/Invoice or Delivery Note.
You can track Sales Personwise commission in the report under Selling module.

View File

@@ -8,7 +8,7 @@ You can manage multiple incoming and outgoing Email Accounts in ERPNext. There h
ERPNext will create templates for a bunch of email accounts by default. Not all of them are enabled. To enable them, you must set your account details.
There are 2 types of email accounts, outgoing and incoming. Outgoing email accounts use an SMTP service to send emails and emails are retrived from your inbox using a POP service. Most email providers such as GMail, Outlook or Yahoo provide these services.
There are 2 types of email accounts, outgoing and incoming. Outgoing email accounts use an SMTP service to send emails and emails are retrived from your inbox using a IMAP or POP service. Most email providers such as GMail, Outlook or Yahoo provide these services.
<img class="screenshot" alt="Defining Criteria" src="{{docs_base_url}}/assets/img/setup/email/email-account-list.png">
@@ -28,7 +28,7 @@ To setup an incoming Email Account, check on **Enable Incoming** and set your PO
### How ERPNext handles replies
In ERPNext when you send an email to a contact like a customer, the sender will be the user who sent the email. In the **Reply-To** property, the Email Address will be of the default incoming account (like `replies@yourcompany.com`). ERPNext will automatically extract these emails from the incoming account and tag it to the relvant communication
In ERPNext when you send an email to a contact like a customer, the sender will be the user who sent the email. In the **Reply-To** property, the Email Address will be of the default incoming account (like `replies@yourcompany.com`). ERPNext will automatically extract these emails from the incoming account and tag it to the relevant communication
### Notification for unreplied messages

View File

@@ -0,0 +1,30 @@
#Setting up Stripe
To setup Stripe,
`Explore > Integrations > Stripe Settings`
#### Setup Stripe
To enable Stripe payment service, you need to configure parameters like Publishable Key, Secret Key
<img class="screenshot" alt="Razorpay Settings" src="{{docs_base_url}}/assets/img/setup/integrations/stripe_setting.png">
On enabling service, the system will create Payment Gateway record and Account head in chart of account with account type as Bank.
<img class="screenshot" alt="Stripe COA" src="{{docs_base_url}}/assets/img/setup/integrations/stripe_coa.png">
Also it will create Payment Gateway Account entry. Payment Gateway Account is configuration hub from this you can set account head from existing COA, default Payment Request email body template.
<img class="screenshot" alt="Payment Gateway Account" src="{{docs_base_url}}/assets/img/setup/integrations/payment_gateway_account_stripe.png">
After configuring Payment Gateway Account your system is able to accept online payments.
####Supporting transaction currencies
"AED", "ALL", "ANG", "ARS", "AUD", "AWG", "BBD", "BDT", "BIF", "BMD", "BND",
"BOB", "BRL", "BSD", "BWP", "BZD", "CAD", "CHF", "CLP", "CNY", "COP", "CRC", "CVE", "CZK", "DJF",
"DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "FKP", "GBP", "GIP", "GMD", "GNF", "GTQ", "GYD",
"HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "ISK", "JMD", "JPY", "KES", "KHR", "KMF",
"KRW", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "MAD", "MDL", "MNT", "MOP", "MRO", "MUR", "MVR",
"MWK", "MXN", "MYR", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "PAB", "PEN", "PGK", "PHP", "PKR",
"PLN", "PYG", "QAR", "RUB", "SAR", "SBD", "SCR", "SEK", "SGD", "SHP", "SLL", "SOS", "STD", "SVC",
"SZL", "THB", "TOP", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VND", "VUV", "WST",
"XAF", "XOF", "XPF", "YER", "ZAR"

View File

@@ -2,7 +2,7 @@
You can globally switch off certain desktop module via:
> Setup > Settings > Show or Hide Modules
> Setup > Permissions > Show / Hide Modules
For example if you are in the services business, you want to hide the Manufacturing Module, you can do this via **Show or Hide Modules**

View File

@@ -12,7 +12,7 @@ app_email = "info@erpnext.com"
app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
develop_version = '8.0.0-beta'
develop_version = '8.x.x-beta'
error_report_email = "support@erpnext.com"

View File

@@ -79,7 +79,7 @@ frappe.ui.form.on('Employee Loan', {
},
employee_loan_application: function(frm) {
return frm.call({
return frappe.call({
method: "erpnext.hr.doctype.employee_loan.employee_loan.get_employee_loan_application",
args: {
"employee_loan_application": frm.doc.employee_loan_application

View File

@@ -14,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -44,6 +45,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,6 +76,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -104,6 +107,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -134,6 +138,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -162,6 +167,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -192,6 +198,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -222,10 +229,12 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "Sanctioned",
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
@@ -237,7 +246,7 @@
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"no_copy": 1,
"options": "Sanctioned\nPartially Disbursed\nFully Disbursed\nRepaid/Closed",
"permlevel": 0,
"precision": "",
@@ -252,6 +261,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -281,6 +291,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -310,6 +321,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -340,6 +352,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -371,6 +384,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -400,6 +414,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -428,6 +443,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -459,6 +475,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -490,6 +507,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -522,6 +540,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -551,6 +570,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -581,6 +601,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -611,6 +632,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -639,6 +661,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -669,6 +692,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -699,6 +723,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -728,6 +753,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -758,6 +784,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -787,6 +814,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -818,6 +846,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -846,6 +875,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -877,6 +907,7 @@
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -916,7 +947,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-30 12:59:40.650035",
"modified": "2017-05-02 13:52:30.884154",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Loan",

View File

@@ -132,7 +132,7 @@ def get_monthly_repayment_amount(repayment_method, loan_amount, rate_of_interest
def get_employee_loan_application(employee_loan_application):
employee_loan = frappe.get_doc("Employee Loan Application", employee_loan_application)
if employee_loan:
return employee_loan
return employee_loan.as_dict()
@frappe.whitelist()
def make_jv_entry(employee_loan, company, employee_loan_account, employee, loan_amount, payment_account):

View File

@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe, math
from frappe import _
from frappe.utils import flt
from frappe.utils import flt, rounded
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
@@ -28,12 +28,28 @@ class EmployeeLoanApplication(Document):
if self.repayment_method == "Repay Fixed Amount per Period":
monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
self.repayment_periods = math.ceil((math.log(self.repayment_amount) - math.log(self.repayment_amount - \
(self.loan_amount*monthly_interest_rate)))/(math.log(1+monthly_interest_rate)))
if monthly_interest_rate:
self.repayment_periods = math.ceil((math.log(self.repayment_amount) -
math.log(self.repayment_amount - (self.loan_amount*monthly_interest_rate))) /
(math.log(1 + monthly_interest_rate)))
else:
self.repayment_periods = self.loan_amount / self.repayment_amount
self.total_payable_amount = self.repayment_amount * self.repayment_periods
self.total_payable_interest = self.total_payable_amount - self.loan_amount
self.calculate_payable_amount()
def calculate_payable_amount(self):
balance_amount = self.loan_amount
self.total_payable_amount = 0
self.total_payable_interest = 0
while(balance_amount > 0):
interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100))
balance_amount = rounded(balance_amount + interest_amount - self.repayment_amount)
self.total_payable_interest += interest_amount
self.total_payable_amount = self.loan_amount + self.total_payable_interest
@frappe.whitelist()
def make_employee_loan(source_name, target_doc = None):
doclist = get_mapped_doc("Employee Loan Application", source_name, {

View File

@@ -39,13 +39,13 @@ class TestEmployeeLoanApplication(unittest.TestCase):
def test_loan_totals(self):
loan_application = frappe.get_doc("Employee Loan Application", {"employee":self.employee})
self.assertEquals(loan_application.repayment_amount, 11445)
self.assertEquals(loan_application.total_payable_interest, 24680)
self.assertEquals(loan_application.total_payable_amount, 274680)
self.assertEquals(loan_application.total_payable_interest, 24657)
self.assertEquals(loan_application.total_payable_amount, 274657)
loan_application.repayment_method = "Repay Fixed Amount per Period"
loan_application.repayment_amount = 15000
loan_application.save()
self.assertEquals(loan_application.repayment_periods, 18)
self.assertEquals(loan_application.total_payable_interest, 20000)
self.assertEquals(loan_application.total_payable_amount, 270000)
self.assertEquals(loan_application.total_payable_interest, 18506)
self.assertEquals(loan_application.total_payable_amount, 268506)

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