Compare commits

...

473 Commits

Author SHA1 Message Date
Pratik Vyas
eda4265dbc Merge branch 'develop' 2015-02-11 13:07:59 +05:30
Pratik Vyas
a9eae0b424 bumped to version 4.21.4 2015-02-11 13:37:59 +06:00
Nabin Hait
c3fc490d53 Merge pull request #2722 from nabinhait/fix1
minor fix in authorization rule
2015-02-11 12:25:16 +05:30
Nabin Hait
108e935744 minor fix in authorization rule 2015-02-11 12:24:45 +05:30
Pratik Vyas
eac82039e3 Merge branch 'develop' 2015-02-09 18:34:23 +05:30
Pratik Vyas
e0a8f2d859 bumped to version 4.21.3 2015-02-09 19:04:23 +06:00
Nabin Hait
fcca772383 Merge pull request #2712 from nabinhait/fix1
UOM validation for BOM Items
2015-02-09 17:02:41 +05:30
Nabin Hait
c5fb88c1cd UOM validation for BOM Items 2015-02-09 16:48:02 +05:30
Pratik Vyas
aacb0a702e Add auto email id in test site_config.json 2015-02-06 16:55:41 +05:30
Pratik Vyas
f3a9d788bf Merge branch 'develop' 2015-02-06 16:32:00 +05:30
Pratik Vyas
6203cf7f04 bumped to version 4.21.2 2015-02-06 17:02:00 +06:00
Nabin Hait
4ec5d5594b Merge pull request #2696 from nabinhait/fix1
net_total and grand_total mismatch issue
2015-02-06 15:43:10 +05:30
Nabin Hait
a3cb828ed3 progress bar in item grid 2015-02-06 13:00:33 +05:30
Nabin Hait
5e13e0c316 net_total and grand_total mismatch issue 2015-02-05 17:18:03 +05:30
Pratik Vyas
bfeb7c4a57 Merge branch 'develop' 2015-02-05 15:44:06 +05:30
Pratik Vyas
43f627a83a bumped to version 4.21.1 2015-02-05 16:14:06 +06:00
Anand Doshi
d0b3a3734e Merge pull request #2693 from anandpdoshi/anand-feb-5
Fixed call to calculate
2015-02-05 15:25:25 +05:30
Nabin Hait
94365fa035 Merge pull request #2694 from nabinhait/fix1
divisional loss adjustment while doing gl entry for purchase receipt
2015-02-05 15:22:28 +05:30
Nabin Hait
e0ce9407cb divisional loss adjustment while doing gl entry for purchase receipt 2015-02-05 15:12:37 +05:30
Anand Doshi
dea3fb0d64 [fix] call calculate code only once after applying pricing rule 2015-02-05 15:06:16 +05:30
Pratik Vyas
1dae1c40b9 Merge branch 'develop' 2015-02-05 14:25:13 +05:30
Pratik Vyas
fd654a06e8 bumped to version 4.21.0 2015-02-05 14:55:13 +06:00
Nabin Hait
5bf1f89da7 Merge pull request #2669 from nathando/patch-2
Look like a minor bug
2015-02-05 13:48:47 +05:30
Nabin Hait
b6c8c7436f Merge pull request #2691 from nabinhait/fix1
item-wise tax distribution if amount entered in actual
2015-02-05 10:31:30 +05:30
Nabin Hait
1dc8ff5220 item-wise tax distribution if amount entered in actual 2015-02-04 18:06:59 +05:30
Nabin Hait
06d81822fd Merge pull request #2673 from nabinhait/fix1
Multiple fixes
2015-02-03 18:32:19 +05:30
Nabin Hait
0c883500bb Expense account query in purchase invoice 2015-02-03 17:59:00 +05:30
Nabin Hait
4ce020f521 Item grid header in print format 2015-02-03 17:59:00 +05:30
Nabin Hait
11cb9de10a Merge pull request #2670 from nabinhait/fix1
default target warehouse for subcontract
2015-02-03 14:34:34 +05:30
Do Le Bao Nguyen
f9b63dd36a Look like a minor bug
- There is no frappe.get_default but only frappe.db.get_default ?
- Error return if selecting Employee in Salary Slip without specifying the Fiscal Year first
2015-02-03 11:10:09 +08:00
Nabin Hait
282695f536 Merge pull request #2664 from neilLasrado/lead-search
lead report - state, country and pincode seprated from address
2015-02-02 17:07:00 +05:30
Neil Trini Lasrado
809abdf295 lead report - state, country and pincode seprated from address 2015-02-02 11:43:56 +05:30
Nabin Hait
79dc136d50 default target warehouse for subcontract 2015-01-29 12:51:17 +05:30
Pratik Vyas
2407d87b0d Merge branch 'develop' 2015-01-28 17:01:56 +05:30
Pratik Vyas
276053b35f bumped to version 4.20.2 2015-01-28 17:31:56 +06:00
Nabin Hait
dc4c2733f4 Merge pull request #2648 from nabinhait/fix1
Print format: show item table header as per meta label
2015-01-28 16:48:38 +05:30
Nabin Hait
f6f2fc4079 Print format: show item table header as per meta label 2015-01-28 16:45:13 +05:30
Nabin Hait
68b5eaa82f Merge pull request #2646 from nabinhait/fix1
Minor fixes
2015-01-28 14:30:55 +05:30
Nabin Hait
238fd68803 Minor fix 2015-01-28 14:30:03 +05:30
Nabin Hait
22a4b82bd2 Minor fixes 2015-01-28 13:11:49 +05:30
Pratik Vyas
f456eb6254 Merge branch 'develop' 2015-01-27 14:43:53 +05:30
Pratik Vyas
408a8e804c bumped to version 4.20.1 2015-01-27 15:13:53 +06:00
Anand Doshi
e0b39b860f Merge pull request #2640 from anandpdoshi/anand-jan-27
Fixes to Error Reports
2015-01-27 14:33:12 +05:30
Anand Doshi
fde7febf0d Merge pull request #2637 from neilLasrado/batch-patch
patch fix for Batch problem
2015-01-27 13:54:52 +05:30
Anand Doshi
eebf194468 Merge pull request #2638 from gitter-badger/gitter-badge-1
Add a Gitter chat badge to README.md
2015-01-27 13:31:05 +05:30
Anand Doshi
6f701b3b6a [minor] Packing Slip get_query 2015-01-27 13:18:01 +05:30
Anand Doshi
8147f74e4e [minor] Mandatory filters in Customer Acquisition and Loyalty 2015-01-27 13:16:18 +05:30
Neil Trini Lasrado
dc65dc3778 rename patch 2015-01-27 12:27:10 +05:30
The Gitter Badger
a7fb9216c9 Added Gitter badge 2015-01-27 06:12:58 +00:00
Neil Trini Lasrado
81b98261ae patch fix 2015-01-27 11:28:56 +05:30
Pratik Vyas
c20072e940 Merge branch 'develop' 2015-01-23 16:16:53 +05:30
Pratik Vyas
e4c2ebfc57 bumped to version 4.20.0 2015-01-23 16:46:53 +06:00
Nabin Hait
587c061550 Merge pull request #2622 from neilLasrado/batch-patch
patch for is_batch_item
2015-01-23 15:45:53 +05:30
Neil Trini Lasrado
40a9f6f8e9 patch fix 2015-01-23 15:32:35 +05:30
Neil Trini Lasrado
f0b0464cce patch for is_batch_item 2015-01-23 15:32:35 +05:30
Nabin Hait
4e803af0e6 Merge pull request #2625 from nabinhait/fix1
Allow nagative batch balance from landed cost voucher
2015-01-23 14:30:31 +05:30
Nabin Hait
4ccd8d3326 Allow nagative batch balance from landed cost voucher 2015-01-23 12:18:14 +05:30
Nabin Hait
9768467d53 Merge pull request #2619 from nabinhait/fix1
POS fix: setting discount amount
2015-01-21 17:53:09 +05:30
Nabin Hait
59de1e23bc POS fix: setting discount amount 2015-01-21 17:50:28 +05:30
Pratik Vyas
f19b1e0c6b Merge branch 'develop' 2015-01-21 17:05:29 +05:30
Pratik Vyas
d33a3a295f bumped to version 4.19.0 2015-01-21 17:35:29 +06:00
Nabin Hait
f749302d25 Merge pull request #2616 from nabinhait/fix1
Fix1
2015-01-21 16:32:28 +05:30
Nabin Hait
9c47efb592 Landed cost voucher: allow negative stock while doing cancellation entry for purchase receipts 2015-01-21 16:22:45 +05:30
Nabin Hait
ea61046e8d Updated Quotation Status 2015-01-21 14:08:06 +05:30
Nabin Hait
3f671ea60f Landed Cost Voucher: Add field and fixed reposting issue 2015-01-21 14:08:06 +05:30
Pratik Vyas
c1a7c3b08b Update .travis.yml 2015-01-21 12:39:26 +05:30
Pratik Vyas
d1225661d2 Translation updates 2015-01-21 12:05:45 +05:30
Rushabh Mehta
302eee9406 Merge pull request #2463 from Steggur/develop
first is translation commit
2015-01-19 17:08:53 +05:30
Nabin Hait
b434464b1c Merge pull request #2604 from nabinhait/fix1
Fixes
2015-01-19 11:10:39 +05:30
Nabin Hait
aabeb38c15 minor fix 2015-01-19 11:07:32 +05:30
Nabin Hait
fe93ea56b6 Minor fixes: escaped characters 2015-01-19 11:07:32 +05:30
Pratik Vyas
b301603740 Merge branch 'develop' 2015-01-17 01:42:05 +05:30
Pratik Vyas
d7ba759844 bumped to version 4.18.1 2015-01-17 02:12:05 +06:00
Nabin Hait
8efe58bd3c Merge pull request #2591 from nabinhait/fix1
Fixes
2015-01-16 12:03:49 +05:30
Nabin Hait
6609938483 Removed validation: target_valuation > source_valuation 2015-01-16 11:59:47 +05:30
Nabin Hait
84662f2db5 minor fix in payment receipt voucher print format 2015-01-16 11:59:47 +05:30
Nabin Hait
da975f5a76 Merge pull request #2581 from nabinhait/fix1
minor fix
2015-01-14 11:49:46 +05:30
Nabin Hait
f34c96bf7a minor fix 2015-01-14 11:49:04 +05:30
Pratik Vyas
0f96f8e68f Merge branch 'develop' 2015-01-14 11:42:45 +05:30
Pratik Vyas
991962b6fd bumped to version 4.18.0 2015-01-14 12:12:45 +06:00
Nabin Hait
c481e27d88 Merge pull request #2565 from alexandre-00/patch-11
Update bom.py
2015-01-14 11:39:08 +05:30
Nabin Hait
56e04e0727 Merge pull request #2576 from nabinhait/fix1
Discount amount in party currency
2015-01-14 11:27:30 +05:30
Nabin Hait
2244ac4d52 Discount amount in party currency 2015-01-12 17:35:37 +05:30
Nabin Hait
024b537b7f Merge pull request #2557 from neilLasrado/spelling-of-approver
Spelling Correction - Leave application #2552
2015-01-12 17:02:10 +05:30
Pratik Vyas
e4ee5c3f1c Update .travis.yml 2015-01-12 12:48:27 +05:30
Pratik Vyas
4b3d99d39a Merge branch 'develop' 2015-01-12 12:14:36 +05:30
Pratik Vyas
47a10f5a39 bumped to version 4.17.0 2015-01-12 12:44:35 +06:00
Nabin Hait
ecb39a5b63 Merge pull request #2571 from nabinhait/fix1
Fixes
2015-01-12 11:04:50 +05:30
Nabin Hait
39c8c9e7b0 Fixes in print format css 2015-01-12 11:04:07 +05:30
Nabin Hait
4e7cc93af9 minor fix in reposting utility 2015-01-12 10:55:48 +05:30
Rushabh Mehta
f8cb1a916e Merge pull request #2570 from dalers/develop
fix web links and clarify install options
2015-01-12 10:47:06 +05:30
Dale Scott
ab2e75e98e Update README.md 2015-01-11 11:04:43 -07:00
Dale Scott
354892b1c6 Update README.md 2015-01-11 11:01:01 -07:00
Dale Scott
abe69afd69 corrections and clarifications
mostly current websites for user guide, forum, ...
2015-01-11 10:38:03 -07:00
Nabin Hait
c72a89aaf8 Merge pull request #2569 from nabinhait/fix1
create material request from production planning tool
2015-01-11 22:04:07 +05:30
Nabin Hait
873d98be2d create material request from production planning tool 2015-01-11 22:01:59 +05:30
Nabin Hait
f1d06b02e7 Merge pull request #2567 from nabinhait/fix1
valuation rate mandatory if item is transacting for the first time
2015-01-10 10:31:34 +05:30
Nabin Hait
675276b802 valuation rate mandatory if item is transacting for the first time 2015-01-10 10:27:28 +05:30
alexandre-00
3ed3a2d176 Update bom.py
removed the attrgetter
2015-01-09 14:42:27 +08:00
Rushabh Mehta
9e95e780da Merge pull request #2560 from neilLasrado/test-fix
opportunity - test records fixed
2015-01-09 12:03:28 +05:30
alexandre-00
de58657537 Update bom.py
Hi guys,

Just a proposal to sort the Materials Required (Exploded) from the BOM.
So the items and sub-assemblies items looks a little bit more organized in the list.

Cheers
Alexandre
2015-01-09 14:20:43 +08:00
Anand Doshi
015fa7a1d1 [fix] escape quote in Accounts Receivable 2015-01-08 18:26:53 +05:30
Neil Trini Lasrado
1ff3a6cdb8 fix 2015-01-07 16:24:52 +05:30
Nabin Hait
7620efc9ad Merge pull request #2561 from nabinhait/fix1
fix reposting gl entries for future vouchers
2015-01-07 15:49:35 +05:30
Nabin Hait
7778b480fd fix reposting gl entries for future vouchers 2015-01-07 15:45:10 +05:30
Neil Trini Lasrado
a17d7cea34 test records fixed 2015-01-07 15:42:59 +05:30
Pratik Vyas
a9cafcb8ae Merge branch 'develop' 2015-01-07 11:37:22 +05:30
Pratik Vyas
bdfd0d1ff9 bumped to version 4.16.0 2015-01-07 12:07:22 +06:00
Nabin Hait
afc8b1a087 Merge pull request #2558 from nabinhait/fix1
message changed
2015-01-07 11:34:42 +05:30
Nabin Hait
6c1773025b fiscal year error message 2015-01-07 11:33:14 +05:30
Neil Trini Lasrado
1b7d66fab6 Update leave_application.js 2015-01-07 11:16:41 +05:30
Nabin Hait
e24365f1f4 message fix 2015-01-06 12:57:23 +05:30
Nabin Hait
fd334bf451 Merge pull request #2551 from nabinhait/fix1
minor fix
2015-01-05 08:20:08 +05:30
Nabin Hait
5515b1ea7f minor fix 2015-01-05 08:18:15 +05:30
Nabin Hait
96d67f5153 Merge pull request #2547 from nabinhait/fix1
minor fix
2015-01-04 17:29:14 +05:30
Nabin Hait
8a00319962 minor fix 2015-01-04 17:27:40 +05:30
Nabin Hait
c6136e4801 Merge pull request #2543 from nabinhait/fix1
FG item and raw material can not be merged
2015-01-02 15:13:17 +05:30
Nabin Hait
0938b5dec6 FG item and raw material can not be merged 2015-01-02 15:12:30 +05:30
Nabin Hait
88f8fcb32e Merge pull request #2542 from nabinhait/fix1
In stock entry, difference account can be non-profit-and-loss account
2015-01-02 14:37:43 +05:30
Nabin Hait
f40ce616a7 In stock entry, difference account can be non-profit-and-loss account 2015-01-02 14:37:01 +05:30
Pratik Vyas
b02788b915 Merge branch 'develop' 2014-12-31 12:41:14 +05:30
Pratik Vyas
b094ee45d7 bumped to version 4.15.4 2014-12-31 13:11:14 +06:00
Nabin Hait
de0c87757a Merge pull request #2539 from nabinhait/fix1
item validation in bom
2014-12-31 12:37:38 +05:30
Nabin Hait
5604f987f2 item validation in bom 2014-12-31 12:37:11 +05:30
Nabin Hait
9d14f0f36a Merge pull request #2538 from nabinhait/fix1
set missing cost center using default
2014-12-30 18:35:14 +05:30
Nabin Hait
a74468b353 set missing cost center using default 2014-12-30 18:33:52 +05:30
Nabin Hait
35f81b24f1 Merge pull request #2537 from nabinhait/fix1
focus on barcode field after adding a row
2014-12-30 17:53:58 +05:30
Nabin Hait
40431cbf89 focus on barcode field after adding a row 2014-12-30 17:53:16 +05:30
Nabin Hait
5529f14aaf Merge pull request #2536 from nabinhait/fix1
Fixes in Stock Analytics
2014-12-30 16:35:57 +05:30
Nabin Hait
54c31b498b Fixes in Stock Analytics 2014-12-30 16:33:07 +05:30
Nabin Hait
899dba9022 Merge pull request #2535 from nabinhait/fix1
always calculate taxes and totals onchange of exchange rate
2014-12-30 15:41:22 +05:30
Nabin Hait
7d8fa8089a always calculate taxes and totals onchange of exchange rate 2014-12-30 15:35:59 +05:30
Pratik Vyas
ac86c5b6d1 Merge branch 'develop' 2014-12-28 16:59:08 +05:30
Pratik Vyas
ecc3f312b9 bumped to version 4.15.3 2014-12-28 17:29:08 +06:00
Nabin Hait
b65b5f43a7 Merge pull request #2530 from nabinhait/fix1
exchange_rate no_copy fix
2014-12-26 11:00:03 +05:30
Nabin Hait
c3270d7504 exchange_rate no_copy fix 2014-12-26 10:58:58 +05:30
Pratik Vyas
ea909ace01 Merge branch 'develop' 2014-12-23 19:11:08 +05:30
Pratik Vyas
f64d11da3c bumped to version 4.15.2 2014-12-23 19:41:08 +06:00
Nabin Hait
95225be93d Merge pull request #2509 from pdvyas/fix-patches
add reload_doc in a few patches
2014-12-23 17:43:52 +05:30
Nabin Hait
e5d169b8d2 Merge pull request #2521 from nabinhait/fix1
fixed negative batch wty message
2014-12-23 11:26:04 +05:30
Nabin Hait
da4e3fb366 fixed negative batch wty message 2014-12-23 10:58:01 +05:30
Nabin Hait
13ce150149 Merge pull request #2520 from nabinhait/fix1
minor fix no-copy
2014-12-22 15:07:28 +05:30
Nabin Hait
a04489a72b minor fix no-copy 2014-12-22 14:58:36 +05:30
Pratik Vyas
35cd88b09b Merge branch 'develop' 2014-12-22 11:17:45 +05:30
Pratik Vyas
ff56566506 bumped to version 4.15.1 2014-12-22 11:47:45 +06:00
Nabin Hait
01ad94bfad Merge pull request #2519 from nabinhait/fix1
Dont reset pricing if ignore pricing rule
2014-12-22 11:16:02 +05:30
Nabin Hait
cfe3c54ca0 Dont reset pricing if ignore pricing rule 2014-12-22 10:43:10 +05:30
Pratik Vyas
2f6a20a93a Merge branch 'develop' 2014-12-19 18:13:55 +05:30
Pratik Vyas
5d1543f241 bumped to version 4.15.0 2014-12-19 18:43:55 +06:00
Nabin Hait
c56650c773 Merge pull request #2516 from nabinhait/fix1
Customer should not copied from lead to opoortunity
2014-12-19 10:52:52 +05:30
Nabin Hait
cb11f27558 Customer should not copied from lead to opoortunity 2014-12-19 10:51:59 +05:30
Anand Doshi
98be98816c Merge pull request #2515 from anandpdoshi/anand-dec-18
[fix] In Setup Wizard, load languages from languages.txt
2014-12-18 17:40:58 +05:30
Anand Doshi
ca2c297f72 [fix] In Setup Wizard, load languages from languages.txt 2014-12-18 17:31:21 +05:30
Pratik Vyas
387e1e21cb add reload_doc in a few patches 2014-12-18 11:36:23 +05:30
Nabin Hait
d6e49150a8 Merge pull request #2505 from nabinhait/fix1
Reapply price list if pricing rule reset as blank
2014-12-17 15:39:28 +05:30
Nabin Hait
49a2729663 Reapply price list if pricing rule reset as blank 2014-12-17 11:24:00 +05:30
Pratik Vyas
06baf20edd Merge branch 'develop' 2014-12-16 15:47:07 +05:30
Pratik Vyas
13553c2bf0 bumped to version 4.14.0 2014-12-16 16:17:06 +06:00
Nabin Hait
f638c1acd5 Merge pull request #2503 from nabinhait/fix1
packing list index
2014-12-16 15:17:27 +05:30
Nabin Hait
e4c659386a packing list index 2014-12-16 15:16:55 +05:30
Anand Doshi
cd7a1661c6 Merge pull request #2498 from anandpdoshi/anand-dec-15
[minor] use frappe.attach_print() in salary slip and recurring document
2014-12-16 12:42:40 +05:30
Nabin Hait
96962e2101 Merge pull request #2501 from nabinhait/fix1
Fecth contact details on change of contact in purchase transactions
2014-12-16 11:57:11 +05:30
Nabin Hait
7eedebc970 Fecth contact details on change of contact in purchase transactions 2014-12-16 11:56:21 +05:30
Nabin Hait
437e34accb Merge pull request #2500 from nabinhait/fix1
no copy property for customer's po no
2014-12-16 11:26:08 +05:30
Nabin Hait
0f2137be18 no copy property for customer's po no 2014-12-16 10:37:55 +05:30
Anand Doshi
f87a622ef0 [minor] use frappe.attach_print() in salary slip and recurring document 2014-12-15 23:14:35 +05:30
Nabin Hait
07722b835c Merge pull request #2495 from nabinhait/fix1
Translation fixes
2014-12-15 15:00:12 +05:30
Nabin Hait
3cd7a45c1b Translation fixes 2014-12-15 14:56:58 +05:30
Nabin Hait
90b5174256 minor fix 2014-12-15 11:48:43 +05:30
Pratik Vyas
bffad26226 Merge branch 'develop' 2014-12-12 16:52:09 +05:30
Pratik Vyas
a578f3e23a bumped to version 4.13.1 2014-12-12 17:22:09 +06:00
Nabin Hait
870dd43268 Merge pull request #2489 from nabinhait/fix1
Pull all customer's po no in delivery note when made from multiple SO
2014-12-12 12:50:41 +05:30
Nabin Hait
ad0bd4ca92 Pull all customer's po no in delivery note when made from multiple sales order 2014-12-12 12:49:45 +05:30
Nabin Hait
eba480e15a Merge pull request #2487 from nabinhait/fix1
Fixed bom patch
2014-12-12 11:29:49 +05:30
Nabin Hait
4b83403a63 Fixed bom patch 2014-12-12 11:28:58 +05:30
Nabin Hait
22c9e42f4d Merge pull request #2482 from neilLasrado/fix-cost
Fixed cost calculation Error
2014-12-11 17:36:49 +05:30
Neil Trini Lasrado
6ddc487fb6 patch fix 2014-12-11 17:33:41 +05:30
Neil Trini Lasrado
3a34cadcb2 Fix - Total Fixed Cost with patch 2014-12-11 17:15:12 +05:30
Nabin Hait
b71d1a4c7f Merge pull request #2486 from nabinhait/fix1
Removed gross profit field from sales invoice
2014-12-11 17:14:26 +05:30
Nabin Hait
bef80bab0d Removed gross profit field from sales invoice 2014-12-11 16:27:18 +05:30
Nabin Hait
190210394c Merge pull request #2484 from nabinhait/fix1
Leave application fix
2014-12-11 00:02:38 +05:30
Nabin Hait
5cafcf66b0 Leave application fix 2014-12-10 23:59:04 +05:30
Nabin Hait
d71e50c9fc Merge pull request #2480 from nabinhait/fix1
Fixes for discount amount
2014-12-10 12:44:56 +05:30
Nabin Hait
35ebe1bf78 Tax amount in POS invoice print format 2014-12-10 12:42:32 +05:30
Nabin Hait
b14cc0417d Display tax amount after discount, if there is any discount amount 2014-12-10 12:28:25 +05:30
Pratik Vyas
399a3097e8 Merge branch 'develop' 2014-12-09 16:40:28 +05:30
Pratik Vyas
c8f5c3cdbe bumped to version 4.13.0 2014-12-09 17:10:28 +06:00
Nabin Hait
e83d506319 Merge pull request #2474 from nabinhait/fix1
Added leave approver name field in leave application
2014-12-09 16:37:40 +05:30
Nabin Hait
690bcd7b66 Added leave approver name field in leave application 2014-12-09 16:36:33 +05:30
Nabin Hait
f18d285eab Merge pull request #2473 from nabinhait/fix1
minor fix
2014-12-09 16:31:03 +05:30
Nabin Hait
7887ccb441 Credit days fix 2014-12-09 14:34:14 +05:30
Nabin Hait
d57b57a21d Minor fix in accounts receivable report 2014-12-09 11:56:13 +05:30
erp
9fc0a8cbf8 first is translation commit 2014-12-05 11:17:44 +00:00
Nabin Hait
5cc0531d27 Merge pull request #2451 from revant/develop
"From time" cannot be later than "To time" and hours cannot be negative
2014-12-02 14:27:00 +05:30
Revant Nandgaonkar
0e5cdc8495 Merge branch 'develop' of https://github.com/revant/erpnext into develop 2014-12-02 14:21:15 +05:30
Revant Nandgaonkar
b80d892eab removed unecessary backslash 2014-12-02 14:19:29 +05:30
Revant Nandgaonkar
185af03fb2 Update time_log.py 2014-12-02 14:18:10 +05:30
Nabin Hait
abcbbc63d8 Merge pull request #2435 from nabinhait/fix1
Fixes in authorization rule based on average discount
2014-12-02 10:36:25 +05:30
Nabin Hait
6871c74ce1 Merge pull request #2444 from ankitjavalkarwork/contactmob
Display mobile no. of contact
2014-12-02 10:35:46 +05:30
Revant Nandgaonkar
d0a44ca85c Changed contact_date to Datetime so appointment or call with time can be scheduled 2014-12-01 23:31:53 +05:30
Revant Nandgaonkar
83db3e3ddb "From time" cannot be later than "To time" and hours cannot be negative 2014-12-01 16:53:29 +05:30
Nabin Hait
cc11045fd3 minor fix 2014-11-28 16:59:32 +05:30
Nabin Hait
1b5afe737f Fixes in authorization rule based on average discount 2014-11-28 16:59:32 +05:30
Rushabh Mehta
3d65d9602e [error-reports] 2014-11-28 14:58:43 +05:30
ankitjavalkarwork
9440d080d4 Print Hide Recurring Order/Invoice based fields 2014-11-27 17:28:53 +05:30
ankitjavalkarwork
9269c86339 Display mobile no of contact 2014-11-27 17:13:36 +05:30
Pratik Vyas
7c82d616c9 Merge branch 'develop' 2014-11-25 11:16:33 +05:30
Pratik Vyas
f227379d2f bumped to version 4.12.0 2014-11-25 11:46:33 +06:00
Nabin Hait
eba88919c1 Merge pull request #2431 from mayur-patel/patch-2
Update leave_application.py : Modified get_holidays function
2014-11-25 10:55:11 +05:30
Rushabh Mehta
3408432b50 Merge pull request #2428 from rmehta/translations-update
[translations] updated via frappe.io/translator
2014-11-25 10:54:36 +05:30
Rushabh Mehta
a0949158b7 [translations] updated via frappe.io/translator 2014-11-25 10:53:12 +05:30
Nabin Hait
ea91d2aaf1 Merge pull request #2429 from ankitjavalkarwork/expclaimname
Add configurable naming series to Expense claim
2014-11-25 10:51:03 +05:30
Rushabh Mehta
de992abf83 Merge pull request #2413 from Delte/patch-1
Update tr.csv
2014-11-25 10:49:51 +05:30
Mayur Patel
5d8635a8dc Update leave_application.py
See issue #2422 for more detail.
2014-11-24 16:57:53 +00:00
ankitjavalkarwork
7e911bae95 Add configurable naming series to Expense claim 2014-11-24 18:26:17 +05:30
Nabin Hait
0676cf6d3f Merge pull request #2430 from nabinhait/fix1
Multiple minor fixes
2014-11-24 18:21:37 +05:30
Nabin Hait
b74ae7aa31 Minor fix for order to invoice mapping 2014-11-24 18:17:01 +05:30
Nabin Hait
0ad7db3bbd Minor fix in salary slip net total calculation 2014-11-24 15:25:13 +05:30
Nabin Hait
db74e316d2 Validate serial no after auto-creation based on naming series 2014-11-24 15:25:13 +05:30
Nabin Hait
1897360e4b Set default language as English in setup wizard 2014-11-24 15:25:13 +05:30
Nabin Hait
e7fb957415 Merge pull request #2427 from rmehta/develop
[fix] client side queries
2014-11-24 15:23:27 +05:30
Rushabh Mehta
2f4567fa3c [minor] [ux] address refresh for lead 2014-11-24 15:18:40 +05:30
Rushabh Mehta
0a7abc188e [minor] [ux] contact template 2014-11-24 15:06:40 +05:30
Rushabh Mehta
5eeef7f065 [refactor] address and contact list in customer, supplier, lead, sales person 2014-11-24 14:16:51 +05:30
Rushabh Mehta
7d36875d6f [refactor] address and contact list in customer, supplier, lead, sales person 2014-11-24 14:16:47 +05:30
Delte
2fa718705a Update tr.csv
Typo & translation fix
2014-11-15 22:39:25 +02:00
Pratik Vyas
b1fdbf2335 Merge branch 'develop' 2014-11-14 15:27:34 +05:30
Pratik Vyas
2277922313 bumped to version 4.11.2 2014-11-14 15:57:34 +06:00
Nabin Hait
3e1029309c Merge pull request #2411 from nabinhait/fix1
minor fix
2014-11-14 15:19:51 +05:30
Nabin Hait
aa5deaa070 minor fix 2014-11-14 15:19:07 +05:30
Nabin Hait
6b5d51ca22 Merge pull request #2402 from jorxzpagta/patch-1
Update supplier.js [Displaying Messages on the Communation History]
2014-11-14 15:05:11 +05:30
Nabin Hait
2c114b5bb5 Merge pull request #2407 from ankitjavalkarwork/packingsliphead
Add letterhead field and mapper in Packing Slip
2014-11-14 14:50:28 +05:30
Nabin Hait
bd38a79e5e Merge pull request #2410 from nabinhait/fix1
Minor fixes
2014-11-14 14:48:02 +05:30
Nabin Hait
ccd9fd3e94 Rounding in totals calculation 2014-11-14 14:27:24 +05:30
Nabin Hait
4215b3afc3 temporary fix in payment tool 2014-11-14 10:51:31 +05:30
ankitjavalkarwork
f60f111afe Add letterhead field and mapper in Packing Slip 2014-11-13 17:28:42 +05:30
jorxzpagta
6fe0a3cee3 Update supplier.js
Display Messages on the Communication History
2014-11-12 17:02:06 +08:00
Nabin Hait
f004077734 Map only pending qty from Material Request to Purchase Order/Stock Entry 2014-11-11 10:51:41 +05:30
Nabin Hait
6c5cfd2148 Merge pull request #2396 from nabinhait/fix1
Reference / Cheque date is after due date
2014-11-10 18:07:52 +05:30
Nabin Hait
6c1011df92 Reference / Cheque date is after due date 2014-11-10 14:57:53 +05:30
Pratik Vyas
1582a0ce78 Merge branch 'develop' 2014-11-10 12:38:45 +05:30
Pratik Vyas
b5b821363d bumped to version 4.11.1 2014-11-10 13:08:45 +06:00
Nabin Hait
399afc87ef Merge pull request #2379 from nathando/develop
Remove get_server_field from leave_application
2014-11-10 12:05:40 +05:30
Nabin Hait
8c842af172 Merge pull request #2393 from nabinhait/fix1
Credit days and payment tool fixes
2014-11-10 11:44:37 +05:30
Nabin Hait
bf836277f9 Payment tool fix: get outstanding sales orders 2014-11-10 11:28:25 +05:30
Nabin Hait
10d1806d81 Credit days validation fixes 2014-11-10 11:11:58 +05:30
Pratik Vyas
bc41ce95fc Merge branch 'develop' 2014-11-06 14:36:51 +05:30
Pratik Vyas
4948d336c4 bumped to version 4.11.0 2014-11-06 15:06:51 +06:00
Nabin Hait
be2527d93d Merge pull request #2386 from nabinhait/fix1
Translation fixed for Croatia
2014-11-06 12:52:59 +05:30
Nabin Hait
7f5bb1c8aa Translation fixed for Croatia 2014-11-06 12:51:27 +05:30
Pratik Vyas
a8d40e4409 Merge branch 'develop' 2014-11-05 14:15:47 +05:30
Pratik Vyas
e9b4686fec bumped to version 4.10.0 2014-11-05 14:45:47 +06:00
Nabin Hait
5086ef2499 Update update_requested_and_ordered_qty.py 2014-11-05 12:33:29 +05:30
Nathan Do
8a55d9a795 Remove get_server_field from leave_application
- Make get_holidays and get_total_leave_days global to module
- Replace get_server_field with using whitelisted function
get_total_leave_days
2014-11-05 12:32:57 +08:00
Nabin Hait
1caca80203 Merge pull request #2378 from nabinhait/fix1
Requested and ordered qty calculation
2014-11-04 18:06:00 +05:30
Nabin Hait
9114c26857 Patch to recalculate requested qty and ordered qty for all items 2014-11-04 15:34:03 +05:30
Nabin Hait
941a965af4 Ordered qty calculation logic 2014-11-04 15:34:03 +05:30
Nabin Hait
4acd431b92 Requested qty calculation logic 2014-11-04 15:34:03 +05:30
Nabin Hait
fad0d566f9 Payment receipt voucher print format fixed 2014-11-04 15:34:03 +05:30
Pratik Vyas
e2d4079363 Merge branch 'develop' 2014-11-03 16:04:30 +05:30
Pratik Vyas
b9ce1f590b bumped to version 4.9.3 2014-11-03 16:34:29 +06:00
Nabin Hait
36463ed790 Merge pull request #2375 from nabinhait/fix1
Check credit limit only if customer debited
2014-11-03 15:55:03 +05:30
Nabin Hait
3c8838816d Check credit limit only if customer debited 2014-11-03 15:49:29 +05:30
Nabin Hait
11e50a8eee Merge pull request #2366 from ankitjavalkarwork/fixprinthideamt
Hide totals in DN, Auto set Bank/Cash acc. in JV
2014-11-03 15:38:45 +05:30
Nabin Hait
9de4c60bd6 Merge pull request #2374 from nabinhait/fix1
minor fix
2014-11-03 15:37:51 +05:30
Nabin Hait
5288bdeabb Minor fix 2014-11-03 15:08:21 +05:30
ankitjavalkarwork
f5804438bb Auto set default bank/cash account on select of Bank/Cash Voucher in JV 2014-11-03 12:23:55 +05:30
ankitjavalkarwork
6e06357dc5 Hide totals on checking print_without_amount field in DN 2014-11-03 11:57:44 +05:30
Nabin Hait
28913b97b0 [fix] Null issue fixed in stock analytics report 2014-10-31 14:46:25 +05:30
Pratik Vyas
c59cd46391 Merge branch 'develop' 2014-10-30 14:22:17 +05:30
Pratik Vyas
dda239fd49 bumped to version 4.9.2 2014-10-30 14:52:17 +06:00
Nabin Hait
b86a6ce26a Merge pull request #2358 from nabinhait/fix1
[fix] Floating point issue fixed in payment reconciliation
2014-10-29 14:26:41 +05:30
Nabin Hait
ee212e7bb5 [fix] Floating point issue fixed in payment reconciliation 2014-10-29 14:26:05 +05:30
Nabin Hait
4952c7b3b5 Merge pull request #2343 from ankitjavalkarwork/fixcustissue
Fix Customer Issue error on click event of Serial No. field
2014-10-27 11:40:18 +05:30
ankitjavalkarwork
4e61536f50 Fix Customer Issue error on click event of Serial No. field 2014-10-27 11:08:05 +05:30
Pratik Vyas
f2886f152b Merge pull request #2348 from pdvyas/fix-pdf-test
Fix PDF test
2014-10-27 10:47:00 +05:30
Pratik Vyas
b5c56f6cea [minor] add port to test site 2014-10-27 09:51:08 +05:30
Pratik Vyas
80e95388f5 Merge branch 'develop' 2014-10-27 09:26:36 +05:30
Pratik Vyas
daed0b655a bumped to version 4.9.1 2014-10-27 09:56:36 +06:00
Nabin Hait
fbb994c731 Merge pull request #2344 from nabinhait/fix1
cost center based on project
2014-10-23 13:30:51 +05:30
Nabin Hait
10b155a486 cost center based on project 2014-10-23 13:18:59 +05:30
Nabin Hait
ce6eda709b Merge pull request #2342 from ankitjavalkarwork/fixtimelogui
Change position of 'To Time' field for better UX
2014-10-22 16:57:52 +05:30
ankitjavalkarwork
14e1d20df3 Change position of 'To Time' field for better UX 2014-10-22 16:55:29 +05:30
Pratik Vyas
da8a02d56e Merge branch 'develop' 2014-10-22 14:19:17 +05:30
Pratik Vyas
16343683d9 bumped to version 4.9.0 2014-10-22 14:49:17 +06:00
Nabin Hait
2bdc017aff Merge pull request #2339 from nabinhait/fix1
Minor fixes
2014-10-22 13:11:21 +05:30
Nabin Hait
16e05c321c Removed stock ageing grid report 2014-10-22 13:10:43 +05:30
Nabin Hait
23d7919865 Stock ageing report fix 2014-10-22 13:06:26 +05:30
Nabin Hait
38265efc39 Minor fix 2014-10-21 20:23:39 +05:30
Rushabh Mehta
2d414706dc [hotfix] translation boo boo 2014-10-21 11:49:40 +05:30
Rushabh Mehta
d85e4b0d46 Merge pull request #2331 from rmehta/translation
[translations] update
2014-10-20 17:12:22 +05:30
Rushabh Mehta
45d03af8f6 [translations] update 2014-10-20 17:11:06 +05:30
Nabin Hait
73a3a2a131 Merge pull request #2327 from nabinhait/stock_reco
Fixes in credit note and quotation
2014-10-20 11:51:01 +05:30
Nabin Hait
73804580d4 validate quotation to lead or customer 2014-10-20 11:18:11 +05:30
Nabin Hait
259f9779db Credit Note: Set total amount and print format fix 2014-10-20 11:18:11 +05:30
Pratik Vyas
14e0e58a7d Merge branch 'develop' 2014-10-17 15:04:05 +05:30
Pratik Vyas
5eb373f7b5 bumped to version 4.8.0 2014-10-17 15:34:05 +06:00
Nabin Hait
4595c30a7b Merge pull request #2322 from nabinhait/stock_reco
Partial payment reconciliation
2014-10-17 15:01:13 +05:30
Nabin Hait
fc2dd44694 Partial payment reconciliation. Fixes #1982 2014-10-17 14:57:20 +05:30
Pratik Vyas
053c54017e [minor] add admin password to travis test site 2014-10-17 14:16:10 +05:30
Pratik Vyas
af473d78f2 Merge branch 'develop' 2014-10-15 15:34:39 +05:30
Pratik Vyas
26d096aa87 bumped to version 4.7.2 2014-10-15 16:04:39 +06:00
Nabin Hait
476c613ba6 Merge pull request #2317 from nabinhait/stock_reco
repost stock utility
2014-10-15 15:33:50 +05:30
Nabin Hait
2348a5f592 repost stock utility 2014-10-15 15:31:33 +05:30
Pratik Vyas
9d8d045c66 Merge branch 'develop' 2014-10-15 14:44:35 +05:30
Pratik Vyas
63914dd55b bumped to version 4.7.1 2014-10-15 15:14:35 +06:00
Nabin Hait
93a8042f08 Merge pull request #2316 from nabinhait/stock_reco
Minor fix
2014-10-15 14:44:06 +05:30
Nabin Hait
b2f32dac1b Minor fix 2014-10-15 14:42:18 +05:30
Pratik Vyas
577a3acaac Merge branch 'develop' 2014-10-15 14:35:47 +05:30
Pratik Vyas
5e46ce8a50 bumped to version 4.7.0 2014-10-15 15:05:47 +06:00
Nabin Hait
3b7342b7b5 Merge pull request #2315 from nabinhait/stock_reco
Strip company in setup wizard
2014-10-15 13:59:07 +05:30
Nabin Hait
531077e504 Strip company in setup wizard 2014-10-15 13:55:37 +05:30
Nabin Hait
147918ed66 Merge pull request #2313 from nabinhait/stock_reco
Fix gl entries for stock transactions
2014-10-15 12:44:59 +05:30
Nabin Hait
9bbfca9226 Fix gl entries for stock transactions 2014-10-15 12:24:38 +05:30
Nabin Hait
f1a07ff105 Allow zero rate while reposting 2014-10-15 12:23:35 +05:30
Nabin Hait
fb6e434315 Guess valuation rate in case of negative stock 2014-10-15 11:34:40 +05:30
Rushabh Mehta
3811d96feb Merge pull request #2308 from devdesco-ceo/patch-1
Update README.md
2014-10-15 10:02:06 +05:30
Viktor Zhuromskyy
1017615d02 Update README.md 2014-10-14 10:12:10 -05:00
Pratik Vyas
056d627f46 Merge branch 'develop' 2014-10-14 17:34:01 +05:30
Pratik Vyas
663bfeacf4 bumped to version 4.6.2 2014-10-14 18:04:01 +06:00
Nabin Hait
e918ebd721 Merge pull request #2307 from nabinhait/stock_reco
Minor fixes
2014-10-14 17:16:32 +05:30
Nabin Hait
0dc18f0102 Minor fixes 2014-10-14 17:15:02 +05:30
Pratik Vyas
8ddc882a66 Merge branch 'develop' 2014-10-14 16:16:29 +05:30
Pratik Vyas
49365d0982 bumped to version 4.6.1 2014-10-14 16:46:29 +06:00
Nabin Hait
50c29c7d0f Merge pull request #2306 from nabinhait/stock_reco
Negative stock in perpetual inventory
2014-10-14 16:10:46 +05:30
Nabin Hait
bf492122f8 minor fix 2014-10-14 16:09:14 +05:30
Nabin Hait
38d0ed9f3a Negative stock allowed for perpetual inventory. Blocked in specific case 2014-10-14 16:08:19 +05:30
Pratik Vyas
248a65b37d Merge branch 'develop' 2014-10-14 12:37:07 +05:30
Pratik Vyas
78f86e9385 bumped to version 4.6.0 2014-10-14 13:07:07 +06:00
Nabin Hait
d9f3e0c275 Merge pull request #2297 from neilLasrado/bom-issue
Fix - BOM calculated wrong cost on update cost
2014-10-14 12:28:16 +05:30
Neil Trini Lasrado
c40451ee2e Patch Fixed 2014-10-14 12:14:39 +05:30
Neil Trini Lasrado
6644406185 Fix - BOM calculated wrong cost on update cost 2014-10-14 12:14:38 +05:30
Nabin Hait
b3a962e121 Merge pull request #2304 from nabinhait/stock_reco
Repost gl entries where mismatch with stock balance
2014-10-14 11:58:41 +05:30
Nabin Hait
8a28ccfa2f Repost gl entries where mismatch with stock balance 2014-10-14 11:41:56 +05:30
Nabin Hait
0a75fa09ef Merge pull request #2300 from nabinhait/stock_reco
Minor fixes
2014-10-13 11:52:00 +05:30
Nabin Hait
17a16eeaf4 Tets case fixed for payment tool 2014-10-13 11:43:14 +05:30
Nabin Hait
3d3f0bcf54 Minor fix in setup wizard 2014-10-13 11:32:41 +05:30
Nabin Hait
bc8b20ae3c Allocate entire advance amount if advance against SO/PO 2014-10-13 10:48:26 +05:30
Nabin Hait
daf344e5fd Precision fixed in batch-wise balance report 2014-10-13 10:48:26 +05:30
Pratik Vyas
7916792f99 Merge pull request #2298 from pdvyas/fix-mariadb
add my_config patch to travis
2014-10-12 19:39:52 +05:30
Pratik Vyas
27e37e68b2 add my_config patch to travis 2014-10-12 19:35:46 +05:30
Nabin Hait
a538f8a24a Merge pull request #2296 from nabinhait/stock_reco
Stock balance report and valuation fixes
2014-10-10 21:23:30 +05:30
Nabin Hait
70ec88b733 fixed test cases 2014-10-10 21:22:46 +05:30
Nabin Hait
4f0e5db216 Stock balance grid report deprecated and moved to server side 2014-10-10 20:54:57 +05:30
Nabin Hait
79ed124939 Update journal_voucher.py 2014-10-10 18:19:03 +05:30
Nabin Hait
c0a3cd603b Merge pull request #2290 from ankitjavalkarwork/accreport
Bug Fixes
2014-10-10 18:11:36 +05:30
Nabin Hait
7c6f990cf9 Minor fix for moving average 2014-10-10 18:03:27 +05:30
Nabin Hait
7820b171d3 Stock balance grid report deprecated and moved to server side 2014-10-10 18:03:07 +05:30
ankitjavalkarwork
0cf4cc283c Add Shipping Addr to Sales Invoice 2014-10-10 16:55:03 +05:30
ankitjavalkarwork
9a4b173b88 Add validation for stopped orders, advance payment in journal voucher 2014-10-10 16:28:41 +05:30
ankitjavalkarwork
6d83454237 Disallow Stopped Orders in Against Voucher table 2014-10-10 13:30:10 +05:30
ankitjavalkarwork
ff231b5e62 Allow advance JV payments in Accounts Receivable/Payable 2014-10-10 13:13:39 +05:30
Nabin Hait
4d74216147 Maintain negative stock balance if balance qty is negative 2014-10-09 19:25:19 +05:30
Nabin Hait
b7e5ad0a31 Merge pull request #2276 from ankitjavalkarwork/sopofield
Rearrange To/From, Recurring Type field for better UX
2014-10-09 11:58:13 +05:30
Pratik Vyas
e435592d64 [minor] Fix default website style patch (reload doc) 2014-10-09 11:22:12 +05:30
Nabin Hait
7ddde8dc3a Merge pull request #2278 from nabinhait/stock_reco
stock reco and repost vouchers
2014-10-08 18:38:54 +05:30
Nabin Hait
fce2881de6 minor fix 2014-10-08 18:38:27 +05:30
Nabin Hait
e96e83d557 stock reco and repost vouchers 2014-10-08 18:06:14 +05:30
ankitjavalkarwork
1b2944e871 Rearrange To/From, Recurring Type field for better UX 2014-10-08 14:24:58 +05:30
Rushabh Mehta
074e73a0dd [translations] updated via translator 2014-10-08 14:16:33 +05:30
Nabin Hait
8923801881 Update stock_entry.py 2014-10-08 13:20:31 +05:30
Nabin Hait
cfafe93391 Merge pull request #2274 from nabinhait/stock_reco
Stock reco
2014-10-08 11:03:03 +05:30
Nabin Hait
6c48ef781b Utility: Repost stock ledger entries and gl entries for all stock transactions 2014-10-08 11:02:18 +05:30
Nabin Hait
adeb976a1b Block negative stock in perpetual inventory 2014-10-08 11:02:18 +05:30
Nabin Hait
bb19b91ef9 stock reco fixes 2014-10-08 11:02:18 +05:30
Nabin Hait
bfa7f171bd Stock reconciliation sl entries 2014-10-08 11:02:18 +05:30
Nabin Hait
b96c014daf Stock Reconciliation logic simplified 2014-10-08 11:02:18 +05:30
Pratik Vyas
e0c83e22d9 Merge branch 'develop' 2014-10-07 17:05:32 +05:30
pdvyas
099ad0f5e1 bumped to version 4.5.2 2014-10-07 17:35:32 +06:00
Nabin Hait
cf9746dd84 Merge pull request #2270 from nabinhait/fix2
Voucher dynamic link in general ledger report
2014-10-07 11:33:40 +05:30
Nabin Hait
b70712dbba Voucher dynamic link in general ledger report 2014-10-07 11:32:54 +05:30
Rushabh Mehta
4c057fe693 Merge pull request #2269 from rmehta/fixes
[fix] packing slip
2014-10-07 11:06:08 +05:30
Nabin Hait
ee8ff51d60 Merge pull request #2261 from ankitjavalkarwork/sopofield
[#2253] Rearrange To/From fields and depend on is_recurring
2014-10-07 10:52:10 +05:30
Rushabh Mehta
9974b16c32 [fix] packing slip 2014-10-07 10:52:05 +05:30
ankitjavalkarwork
9e5f319d80 [#2253] Rearrange To/From fields and depend on is_recurring in SI,SO,PI,PO 2014-10-06 12:58:38 +05:30
Nabin Hait
4f614b4030 Merge pull request #2195 from neilLasrado/manufacture-and-repack
[fix] Issue #2183 - Manufacturing and repack seprated in stock entry
2014-09-30 15:11:05 +05:30
Nabin Hait
3d458e973e Merge pull request #2236 from neilLasrado/upstream/develop
Has Batch No field should be freezed #2023
2014-09-30 14:56:15 +05:30
Neil Trini Lasrado
3a19a71262 patch fixed 2014-09-30 14:48:38 +05:30
Neil Trini Lasrado
29d1a1c593 manufacturing and repack sepreted, test cases fixed, patch fixed 2014-09-30 14:07:56 +05:30
Neil Trini Lasrado
3b90de558f Has Batch No field should be freezed #2023 2014-09-30 12:57:32 +05:30
Nabin Hait
af7e31acb3 Merge pull request #2235 from adityaduggal/develop
Added the dynamic link field in the accounts receivable report.
2014-09-30 10:39:40 +05:30
Aditya Duggal
a2c9d35efb Added the dynamic link field. 2014-09-29 17:44:28 +05:30
Aditya Duggal
4c058f4056 Added the dynamic link and removed the link column 2014-09-29 17:41:19 +05:30
Pratik Vyas
ad67b84d43 Merge branch 'develop' 2014-09-29 15:40:04 +05:30
Pratik Vyas
4e81e4065b bumped to version 4.5.1 2014-09-29 16:10:04 +06:00
Nabin Hait
81332789cb Merge pull request #2232 from nabinhait/hotfix
Fix gl entries for stock transactions
2014-09-29 15:25:02 +05:30
Nabin Hait
82d7c0c9eb Patch: Fix gl entries for stock transactions 2014-09-29 15:07:51 +05:30
Nabin Hait
d60235e239 minor fix in warehouse-wise stock balance report 2014-09-29 11:36:06 +05:30
Nabin Hait
9b50b0a762 Fixes for item list view 2014-09-29 11:36:06 +05:30
Pratik Vyas
21e14c4c98 Merge branch 'develop' 2014-09-26 16:49:59 +05:30
Pratik Vyas
16edacebc7 bumped to version 4.5.0 2014-09-26 17:19:59 +06:00
Nabin Hait
75027b4d54 Merge pull request #2225 from nabinhait/hotfix
GL Entries for future stock voucher and multiple minor fixes
2014-09-26 14:48:56 +05:30
Nabin Hait
b0bd99266d Fix in landed cost voucher 2014-09-26 14:30:02 +05:30
Nabin Hait
b9e04815f8 Repost gl entries for future stock vouchers 2014-09-26 14:24:42 +05:30
Nabin Hait
18ccc27b1b Minor fix in naming naming series 2014-09-26 14:23:00 +05:30
Nabin Hait
95f1fe92e2 Maintenance visit search field issue fixed 2014-09-26 14:23:00 +05:30
Nabin Hait
b783f519ee Fixes in sales/purchase invoice trends report 2014-09-26 14:23:00 +05:30
Nabin Hait
996a1010cb Moved Installation note from tools to documents section 2014-09-26 14:23:00 +05:30
Anand Doshi
32a9dfd983 Merge branch 'sbkolate-develop' into develop 2014-09-22 13:19:24 +05:30
Anand Doshi
1394509343 Fixes for recurring document 2014-09-21 19:45:49 +05:30
Pratik Vyas
0f31c36b2c Merge branch 'develop' 2014-09-19 14:46:07 +05:30
Pratik Vyas
14ac8f71b7 bumped to version 4.4.2 2014-09-19 15:16:07 +06:00
Nabin Hait
6a92d51383 Merge pull request #2212 from nabinhait/hotfix
Fetch and validate advance entries in sales/purchase invoice
2014-09-19 14:41:20 +05:30
Nabin Hait
7c831c3fe5 Get advance in sales/purchase invoice 2014-09-19 14:31:49 +05:30
Nabin Hait
778ff463af Minor fix in authorization control 2014-09-19 11:39:47 +05:30
Nabin Hait
70a31d5402 Gantt view fix for translations 2014-09-19 11:18:10 +05:30
Nabin Hait
48f5fa69f3 Fetch and validate advance entries in sales/purchase invoice 2014-09-18 15:04:11 +05:30
Pratik Vyas
83a2d12cd2 Merge branch 'develop' 2014-09-18 14:19:15 +05:30
Pratik Vyas
e539297e53 bumped to version 4.4.1 2014-09-18 14:49:14 +06:00
Nabin Hait
bbc3d015a3 Update authorization_control.py 2014-09-18 14:09:20 +05:30
Nabin Hait
e4475c635d Merge pull request #2211 from nabinhait/hotfix
Escaped single quote in authorization control queries
2014-09-18 13:01:33 +05:30
Anand Doshi
8370cb3e71 Merge branch 'develop' of https://github.com/sbkolate/erpnext into sbkolate-develop 2014-09-18 12:06:05 +05:30
Nabin Hait
4073880ecf Escaped single quote in authorization control queries 2014-09-18 11:01:26 +05:30
Nabin Hait
763c7a56dc Merge pull request #2209 from nabinhait/hotfix
Minor fix in gross profit report
2014-09-17 14:02:51 +05:30
Nabin Hait
556fbc487d Minor fix in gross profit report 2014-09-17 12:13:44 +05:30
Pratik Vyas
54938d431c Merge branch 'develop' 2014-09-16 15:58:28 +05:30
Pratik Vyas
31c61e7eae bumped to version 4.4.0 2014-09-16 16:28:28 +06:00
Anand Doshi
a23151b138 Merge pull request #2202 from 81552433qqcom/develop
hotfix for project wise report and translation.
2014-09-16 15:23:34 +05:30
Anand Doshi
11b75759d2 Merge pull request #2194 from ankitjavalkarwork/stockbalreport
Update report with Valuation rate, stock values, move to Main report
2014-09-16 15:22:25 +05:30
Rushabh Mehta
a2c562fea4 Update CONTRIBUTING.md 2014-09-16 15:21:43 +05:30
Anand Doshi
8950abc36f Merge pull request #2197 from anandpdoshi/anand-september-15
[minor] removed Suggest
2014-09-16 15:18:57 +05:30
Anand Doshi
27c7226d97 Merge pull request #2201 from nabinhait/hotfix
Columns added in report and fixes in customer's account creation
2014-09-16 15:18:31 +05:30
81552433qqcom
1db294e837 hotfix for project wise report
translation patch for email digest and support ticket.
2014-09-16 16:49:58 +08:00
Nabin Hait
16e943f120 Removed link of item-wise last purchase rate from buying home page 2014-09-16 12:57:31 +05:30
Nabin Hait
9d610214cf Strip party name before checking for account 2014-09-16 12:28:40 +05:30
Nabin Hait
c25681c36c Added item group and brand in sales-person-wise transaction summary report 2014-09-16 12:28:40 +05:30
Nabin Hait
1aea75261d Merge pull request #2200 from nabinhait/hotfix
Minor fix
2014-09-16 11:28:15 +05:30
Nabin Hait
5cd20e3d24 Minor fix 2014-09-16 11:26:53 +05:30
Nabin Hait
9968c7ef70 Merge pull request #2199 from nabinhait/hotfix
Minor fix
2014-09-16 11:25:06 +05:30
Nabin Hait
ca260618d8 Minor fix 2014-09-16 11:24:25 +05:30
Anand Doshi
30c5b41398 [minor] removed Suggest 2014-09-15 16:43:34 +05:30
Sambhaji Kolate
f37d4337a4 fix test for purchase order 2014-09-15 13:37:46 +05:30
Anand Doshi
93c2adb2cd Merge pull request #2193 from anandpdoshi/anand-september-15
Recurring fix, cherry-picked nabin's address template fix
2014-09-15 13:04:12 +05:30
Sambhaji Kolate
525ab0a925 fix build 2014-09-15 12:57:58 +05:30
Anand Doshi
a92c6886cd Merge pull request #2173 from ankitjavalkarwork/fix2043
Add message on cancel in SI if C-Form exists, fix minor error, Add validation in C-Form
2014-09-15 12:56:51 +05:30
Anand Doshi
01d171756b [fix] before_recurring, set due_date, ageing_date as None, fixed account due date validation 2014-09-15 12:50:37 +05:30
Sambhaji Kolate
930e7f5578 fix conflict 2014-09-15 12:43:48 +05:30
Sambhaji Kolate
d14e15d432 fix conflict 2014-09-15 12:31:44 +05:30
Sambhaji Kolate
4d3a18890b fix conflict 2014-09-15 12:20:11 +05:30
Nabin Hait
65bef02607 Fixes in address template 2014-09-15 12:18:28 +05:30
Rushabh Mehta
cb9331ddca Merge pull request #2191 from 81552433qqcom/develop
#2190 hotfix, item page
2014-09-15 10:13:09 +05:30
81552433qqcom
ac0c3fb696 #2190 hotfix, item page 2014-09-15 10:21:36 +08:00
Anand Doshi
a844fb78bb Merge branch '81552433qqcom-master' into develop 2014-09-12 16:23:08 +05:30
81552433qqcom
6d02939256 changed indent. as well use tab instead of space. 2014-09-12 16:22:28 +05:30
81552433qqcom
e3b63f2d9c added __() for options that need label. 2014-09-12 16:07:12 +05:30
81552433qqcom
1c440b3b31 month options doesn't get translated. 2014-09-12 16:07:12 +05:30
81552433qqcom
c5a0ef8399 fix according to the suggestion. 2014-09-12 16:07:12 +05:30
81552433qqcom
951da0ca3d added translations to report py file. 2014-09-12 16:07:12 +05:30
81552433qqcom
351be9ca42 translations. 2014-09-12 16:07:11 +05:30
81552433qqcom
4bab0a2f54 various translation missed __() 2014-09-12 16:07:11 +05:30
Anand Doshi
97478b746d Merge pull request #2185 from anandpdoshi/ankit-payment-tool
Payment Tool
2014-09-12 15:53:03 +05:30
Anand Doshi
61a591944b [minor] ui/ux fixes in Payment Tool 2014-09-12 15:42:16 +05:30
Ankit Javalkar
8e7ca41817 Payment Tool #2106 2014-09-12 15:23:46 +05:30
Anand Doshi
84e08fd534 Merge pull request #2174 from neilLasrado/cost-of-production-cycle-magix
Cost of Production cycle
2014-09-12 14:45:19 +05:30
Anand Doshi
b0e56fa1b5 Merge pull request #2181 from nabinhait/hotfix
Report print format fixed for translated columns
2014-09-12 14:18:52 +05:30
Neil Trini Lasrado
e7c48ed3b0 bom operation inList view fix 2014-09-12 12:08:02 +05:30
Nabin Hait
c432270ca8 Report print format fixed for translated columns 2014-09-12 12:00:47 +05:30
Neil Trini Lasrado
6a7f75c3e3 Cost of Production cycle 2014-09-12 11:25:03 +05:30
Neil Trini Lasrado
e9882e12ba Cost of Production cycle 2014-09-12 11:25:03 +05:30
ankitjavalkarwork
3df10429db Add message on cancel in SI if C-Form exists, Add validation in C-Form, remove update_c_form 2014-09-11 16:58:18 +05:30
Anand Doshi
eee569bb20 Merge pull request #2177 from anandpdoshi/anand-september-11
[fix] transfer_qty in get_stock_and_rate
2014-09-11 16:47:59 +05:30
ankitjavalkarwork
2e07305616 Update report with Valuation rate, stock values, move to Main report 2014-09-11 16:47:19 +05:30
Anand Doshi
2f9c36a588 Merge pull request #2175 from ankitjavalkarwork/fix2153
[minor] Add Permission for additional roles to Customer, Supplier
2014-09-11 16:47:08 +05:30
Anand Doshi
907494c5d4 [fix] transfer_qty in get_stock_and_rate 2014-09-11 16:22:12 +05:30
Sambhaji Kolate
b14401c320 change convert_to_recurring() to take recurring_id dynamicaly 2014-09-11 16:09:05 +05:30
Anand Doshi
4d2520ea53 Merge pull request #2176 from nabinhait/hotfix
Opening entry should not be considered in bank reconciliation statement
2014-09-11 15:21:24 +05:30
Nabin Hait
cece0c7ffe Opening entry should not be considered in bank reconciliation statement 2014-09-11 13:59:00 +05:30
ankitjavalkarwork
5e34383e25 [minor] Add Permission for additional roles to Customer, Supplier 2014-09-10 17:54:42 +05:30
Sambhaji Kolate
b2a3f2d386 some minor changes get fixed for PO/PI 2014-09-10 17:40:48 +05:30
Anand Doshi
8e39ee79b0 Merge pull request #2167 from anandpdoshi/anand-september-9
Set allow_on_submit for 'page_break', 'letter_head', 'select_print_heading', 'print_heading'. Fixes frappe/erpnext#1810
2014-09-10 15:24:52 +05:30
Sambhaji Kolate
6b679c45df Updated purchase_invoice.json and purchase_order.json with some missed out changes 2014-09-10 13:57:45 +05:30
Sambhaji Kolate
e3d2643f2b Changes for Recurring PO/PI 2014-09-10 13:07:59 +05:30
Anand Doshi
fc33d5a75b Set allow_on_submit for 'page_break', 'letter_head', 'select_print_heading', 'print_heading'. Fixes frappe/erpnext#1810 2014-09-09 15:25:43 +05:30
301 changed files with 19323 additions and 13731 deletions

View File

@@ -14,8 +14,11 @@ install:
- sudo apt-get update
- sudo apt-get purge -y mysql-common
- sudo apt-get install mariadb-server mariadb-common libmariadbclient-dev
- wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.1/wkhtmltox-0.12.1_linux-precise-amd64.deb
- sudo dpkg -i wkhtmltox-0.12.1_linux-precise-amd64.deb
- ./ci/fix-mariadb.sh
- sudo apt-get install xfonts-75dpi xfonts-base -y
- wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
- sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
- CFLAGS=-O0 pip install git+https://github.com/frappe/frappe.git@develop
- CFLAGS=-O0 pip install --editable .

View File

@@ -1,5 +1,9 @@
# Contributing to Frappe / ERPNext
### Update 16-Sep-14
Please send pull requests to branch v5.0
## Reporting issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.

View File

@@ -1,34 +1,33 @@
# ERPNext - Open Source ERP for small, medium sized businesses [![Build Status](https://travis-ci.org/frappe/erpnext.png)](https://travis-ci.org/frappe/erpnext)
# ERPNext - Open source ERP for small and medium-size business [![Build Status](https://travis-ci.org/frappe/erpnext.png)](https://travis-ci.org/frappe/erpnext)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/frappe/erpnext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[https://erpnext.com](https://erpnext.com)
Includes Accounting, Inventory, CRM, Sales, Purchase, Projects, HRMS. Built on Python / MariaDB.
Includes: Accounting, Inventory, CRM, Sales, Purchase, Projects, HRMS. Requires MariaDB.
ERPNext is built on [frappe](https://github.com/frappe/frappe)
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & Javascript.
- [User Guide](http://erpnext.org/user-guide.html)
- [User Guide](https://erpnext.com/user-guide)
- [Getting Help](http://erpnext.org/getting-help.html)
- [Developer Forum](http://groups.google.com/group/erpnext-developer-forum)
- [User Forum](http://groups.google.com/group/erpnext-user-forum)
- [Discussion Forum](https://discuss.frappe.io/)
---
### Install
### Full Install
Use the bench, https://github.com/frappe/bench
The Easy Way install script for bench will install all dependencies (e.g. MariaDB). See https://github.com/frappe/bench
### Admin Login
New passwords will be created for the ERPNext "Administrator" user, the MariaDB root user, and the frappe user (the script displays the passwords and saves them to ~/frappe_passwords.txt).
1. go to "/login"
1. Administrator user name: "Administrator"
1. Administrator passowrd "admin"
### Virtual Image
### Download and Install
##### Virtual Image:
You can download a virtual image to run ERPNext in a virtual machine on your local system.
- [ERPNext Download](http://erpnext.com/download)
System and user credentials are listed on the download page.
---
## License

11
ci/fix-mariadb.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
# stolen from http://cgit.drupalcode.org/octopus/commit/?id=db4f837
includedir=`mysql_config --variable=pkgincludedir`
thiscwd=`pwd`
_THIS_DB_VERSION=`mysql -V 2>&1 | tr -d "\n" | cut -d" " -f6 | awk '{ print $1}' | cut -d"-" -f1 | awk '{ print $1}' | sed "s/[\,']//g"`
if [ "$_THIS_DB_VERSION" = "5.5.40" ] && [ ! -e "$includedir-$_THIS_DB_VERSION-fixed.log" ] ; then
cd $includedir
sudo patch -p1 < $thiscwd/ci/my_config.h.patch &> /dev/null
sudo touch $includedir-$_THIS_DB_VERSION-fixed.log
fi

22
ci/my_config.h.patch Normal file
View File

@@ -0,0 +1,22 @@
diff -burp a/my_config.h b/my_config.h
--- a/my_config.h 2014-10-09 19:32:46.000000000 -0400
+++ b/my_config.h 2014-10-09 19:35:12.000000000 -0400
@@ -641,17 +641,4 @@
#define SIZEOF_TIME_T 8
/* #undef TIME_T_UNSIGNED */
-/*
- stat structure (from <sys/stat.h>) is conditionally defined
- to have different layout and size depending on the defined macros.
- The correct macro is defined in my_config.h, which means it MUST be
- included first (or at least before <features.h> - so, practically,
- before including any system headers).
-
- __GLIBC__ is defined in <features.h>
-*/
-#ifdef __GLIBC__
-#error <my_config.h> MUST be included first!
-#endif
-
#endif

View File

@@ -1 +1 @@
__version__ = '4.3.0'
__version__ = '4.21.4'

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cstr, cint, getdate, add_days, formatdate
from frappe.utils import flt, cstr, cint, getdate
from frappe import msgprint, throw, _
from frappe.model.document import Document
@@ -169,24 +169,14 @@ class Account(Document):
def validate_due_date(self, posting_date, due_date):
credit_days = (self.credit_days or frappe.db.get_value("Company", self.company, "credit_days"))
if credit_days is None:
return
posting_date, due_date = getdate(posting_date), getdate(due_date)
diff = (due_date - posting_date).days
if diff < 0:
frappe.throw(_("Due Date cannot be before Posting Date"))
elif diff > credit_days:
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
"credit_controller") in frappe.user.get_roles()
if is_credit_controller:
msgprint(_("Note: Due Date exceeds the allowed credit days by {0} day(s)").format(
diff - credit_days))
else:
max_due_date = formatdate(add_days(posting_date, credit_days))
frappe.throw(_("Due Date cannot be after {0}").format(max_due_date))
elif credit_days is not None and diff > credit_days:
msgprint(_("Note: Due Date exceeds the allowed credit days by {0} day(s)").format(diff - credit_days))
def validate_trash(self):
"""checks gl entries and if child exists"""

View File

@@ -17,15 +17,19 @@ class CForm(Document):
inv = frappe.db.sql("""select c_form_applicable, c_form_no from
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
if inv[0][0] != 'Yes':
if inv and inv[0][0] != 'Yes':
frappe.throw("C-form is not applicable for Invoice: %s" % d.invoice_no)
elif inv[0][1] and inv[0][1] != self.name:
elif inv and inv[0][1] and inv[0][1] != self.name:
frappe.throw("""Invoice %s is tagged in another C-form: %s.
If you want to change C-form no for this invoice,
please remove invoice no from the previous c-form and then try again""" %
(d.invoice_no, inv[0][1]))
elif not inv:
frappe.throw("Row %s: Invoice %s is invalid, it might be cancelled / does not exist. \
Please enter a valid Invoice" % d.idx, d.invoice_no)
def on_update(self):
""" Update C-Form No on invoices"""
self.set_total_invoiced_amount()

View File

@@ -25,7 +25,8 @@ class GLEntry(Document):
validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher
if self.against_voucher and update_outstanding == 'Yes':
if self.against_voucher_type in ['Journal Voucher', 'Sales Invoice', 'Purchase Invoice'] \
and self.against_voucher and update_outstanding == 'Yes':
update_outstanding_amt(self.account, self.against_voucher_type,
self.against_voucher)
@@ -123,6 +124,10 @@ def update_outstanding_amt(account, against_voucher_type, against_voucher, on_ca
from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s
and account = %s and ifnull(against_voucher, '') = ''""",
(against_voucher, account))[0][0])
if not against_voucher_amount:
frappe.throw(_("Against Journal Voucher {0} is already adjusted against some other voucher")
.format(against_voucher))
bal = against_voucher_amount + bal
if against_voucher_amount < 0:
bal = -bal

View File

@@ -213,10 +213,11 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
return;
var update_jv_details = function(doc, r) {
$.each(r.message, function(i, d) {
var jvdetail = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
jvdetail.account = d.account;
jvdetail.balance = d.balance;
var jvdetail = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
$.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Voucher Detail", "entries");
row.account = d.account;
row.balance = d.balance;
});
refresh_field("entries");
}
@@ -231,7 +232,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
},
callback: function(r) {
if(r.message) {
update_jv_details(doc, r);
update_jv_details(doc, [r.message]);
}
}
})
@@ -245,7 +246,7 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
callback: function(r) {
frappe.model.clear_table(doc, "entries");
if(r.message) {
update_jv_details(doc, r);
update_jv_details(doc, r.message);
}
cur_frm.set_value("is_opening", "Yes")
}

View File

@@ -339,6 +339,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
@@ -446,7 +447,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-14 01:37:14.822939",
"modified": "2014-09-09 05:35:31.217863",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Voucher",

View File

@@ -4,8 +4,8 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _, scrub
from erpnext.setup.utils import get_company_currency
from erpnext.controllers.accounts_controller import AccountsController
@@ -13,10 +13,6 @@ from erpnext.controllers.accounts_controller import AccountsController
class JournalVoucher(AccountsController):
def __init__(self, arg1, arg2=None):
super(JournalVoucher, self).__init__(arg1, arg2)
self.master_type = {}
self.credit_days_for = {}
self.credit_days_global = -1
self.is_approving_authority = -1
def validate(self):
if not self.is_opening:
@@ -35,18 +31,35 @@ class JournalVoucher(AccountsController):
self.create_remarks()
self.set_aging_date()
self.set_print_format_fields()
self.validate_against_sales_order()
self.validate_against_purchase_order()
def on_submit(self):
if self.voucher_type in ['Bank Voucher', 'Contra Voucher', 'Journal Entry']:
self.check_credit_days()
self.check_reference_date()
self.make_gl_entries()
self.check_credit_limit()
self.update_advance_paid()
def update_advance_paid(self):
advance_paid = frappe._dict()
for d in self.get("entries"):
if d.is_advance:
if d.against_sales_order:
advance_paid.setdefault("Sales Order", []).append(d.against_sales_order)
elif d.against_purchase_order:
advance_paid.setdefault("Purchase Order", []).append(d.against_purchase_order)
for voucher_type, order_list in advance_paid.items():
for voucher_no in list(set(order_list)):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def on_cancel(self):
from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doctype, self.name, "against_jv")
self.make_gl_entries(1)
self.update_advance_paid()
def validate_cheque_info(self):
if self.voucher_type in ['Bank Voucher']:
@@ -59,25 +72,36 @@ class JournalVoucher(AccountsController):
def validate_entries_for_advance(self):
for d in self.get('entries'):
if not d.is_advance and not d.against_voucher and \
not d.against_invoice and not d.against_jv:
if not (d.against_voucher and d.against_invoice and d.against_jv):
master_type = frappe.db.get_value("Account", d.account, "master_type")
if (master_type == 'Customer' and flt(d.credit) > 0) or \
(master_type == 'Supplier' and flt(d.debit) > 0):
msgprint(_("Please check 'Is Advance' against Account {0} if this is an advance entry.").format(d.account))
if not d.is_advance:
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account))
elif (d.against_sales_order or d.against_purchase_order) and d.is_advance != "Yes":
frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))
def validate_against_jv(self):
for d in self.get('entries'):
if d.against_jv:
account_root_type = frappe.db.get_value("Account", d.account, "root_type")
if account_root_type == "Asset" and flt(d.debit) > 0:
frappe.throw(_("For {0}, only credit entries can be linked against another debit entry")
.format(d.account))
elif account_root_type == "Liability" and flt(d.credit) > 0:
frappe.throw(_("For {0}, only debit entries can be linked against another credit entry")
.format(d.account))
if d.against_jv == self.name:
frappe.throw(_("You can not enter current voucher in 'Against Journal Voucher' column"))
against_entries = frappe.db.sql("""select * from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s
and ifnull(against_jv, '') = ''""", (d.account, d.against_jv), as_dict=True)
and ifnull(against_jv, '') = '' and ifnull(against_invoice, '') = ''
and ifnull(against_voucher, '') = ''""", (d.account, d.against_jv), as_dict=True)
if not against_entries:
frappe.throw(_("Journal Voucher {0} does not have account {1} or already matched")
frappe.throw(_("Journal Voucher {0} does not have account {1} or already matched against other voucher")
.format(d.against_jv, d.account))
else:
dr_or_cr = "debit" if d.credit > 0 else "credit"
@@ -90,24 +114,89 @@ class JournalVoucher(AccountsController):
.format(d.against_jv, dr_or_cr))
def validate_against_sales_invoice(self):
for d in self.get("entries"):
if d.against_invoice:
if d.debit > 0:
frappe.throw(_("Row {0}: Debit entry can not be linked with a Sales Invoice")
.format(d.idx))
if frappe.db.get_value("Sales Invoice", d.against_invoice, "debit_to") != d.account:
frappe.throw(_("Row {0}: Account does not match with \
Sales Invoice Debit To account").format(d.idx, d.account))
payment_against_voucher = self.validate_account_in_against_voucher("against_invoice", "Sales Invoice")
self.validate_against_invoice_fields("Sales Invoice", payment_against_voucher)
def validate_against_purchase_invoice(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_voucher", "Purchase Invoice")
self.validate_against_invoice_fields("Purchase Invoice", payment_against_voucher)
def validate_against_sales_order(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_sales_order", "Sales Order")
self.validate_against_order_fields("Sales Order", payment_against_voucher)
def validate_against_purchase_order(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_purchase_order", "Purchase Order")
self.validate_against_order_fields("Purchase Order", payment_against_voucher)
def validate_account_in_against_voucher(self, against_field, doctype):
payment_against_voucher = frappe._dict()
field_dict = {'Sales Invoice': "Debit To",
'Purchase Invoice': "Credit To",
'Sales Order': "Customer",
'Purchase Order': "Supplier"
}
for d in self.get("entries"):
if d.against_voucher:
if flt(d.credit) > 0:
frappe.throw(_("Row {0}: Credit entry can not be linked with a Purchase Invoice")
.format(d.idx))
if frappe.db.get_value("Purchase Invoice", d.against_voucher, "credit_to") != d.account:
frappe.throw(_("Row {0}: Account does not match with \
Purchase Invoice Credit To account").format(d.idx, d.account))
if d.get(against_field):
dr_or_cr = "credit" if against_field in ["against_invoice", "against_sales_order"] \
else "debit"
if against_field in ["against_invoice", "against_sales_order"] \
and flt(d.debit) > 0:
frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, doctype))
if against_field in ["against_voucher", "against_purchase_order"] \
and flt(d.credit) > 0:
frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, doctype))
voucher_account = frappe.db.get_value(doctype, d.get(against_field), \
scrub(field_dict.get(doctype)))
account_master_name = frappe.db.get_value("Account", d.account, "master_name")
if against_field in ["against_invoice", "against_voucher"] \
and voucher_account != d.account:
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} account") \
.format(d.idx, d.account, doctype, field_dict.get(doctype)))
if against_field in ["against_sales_order", "against_purchase_order"]:
if voucher_account != account_master_name:
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} Name") \
.format(d.idx, d.account, doctype, field_dict.get(doctype)))
elif d.is_advance == "Yes":
payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
return payment_against_voucher
def validate_against_invoice_fields(self, doctype, payment_against_voucher):
for voucher_no, payment_list in payment_against_voucher.items():
voucher_properties = frappe.db.get_value(doctype, voucher_no,
["docstatus", "outstanding_amount"])
if voucher_properties[0] != 1:
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
if flt(voucher_properties[1]) < flt(sum(payment_list)):
frappe.throw(_("Payment against {0} {1} cannot be greater \
than Outstanding Amount {2}").format(doctype, voucher_no, voucher_properties[1]))
def validate_against_order_fields(self, doctype, payment_against_voucher):
for voucher_no, payment_list in payment_against_voucher.items():
voucher_properties = frappe.db.get_value(doctype, voucher_no,
["docstatus", "per_billed", "status", "advance_paid", "grand_total"])
if voucher_properties[0] != 1:
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
if flt(voucher_properties[1]) >= 100:
frappe.throw(_("{0} {1} is fully billed").format(doctype, voucher_no))
if cstr(voucher_properties[2]) == "Stopped":
frappe.throw(_("{0} {1} is stopped").format(doctype, voucher_no))
if flt(voucher_properties[4]) < flt(voucher_properties[3]) + flt(sum(payment_list)):
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
than Grand Total {2}").format(doctype, voucher_no, voucher_properties[3]))
def set_against_account(self):
accounts_debited, accounts_credited = [], []
@@ -147,7 +236,13 @@ class JournalVoucher(AccountsController):
for d in self.get('entries'):
if d.against_invoice and d.credit:
currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
r.append(_("{0} {1} against Invoice {2}").format(currency, fmt_money(flt(d.credit)), d.against_invoice))
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_invoice))
if d.against_sales_order and d.credit:
currency = frappe.db.get_value("Sales Order", d.against_sales_order, "currency")
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_sales_order))
if d.against_voucher and d.debit:
bill_no = frappe.db.sql("""select bill_no, bill_date, currency
@@ -158,13 +253,17 @@ class JournalVoucher(AccountsController):
fmt_money(flt(d.debit)), bill_no[0][0],
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
if d.against_purchase_order and d.debit:
currency = frappe.db.get_value("Purchase Order", d.against_purchase_order, "currency")
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_purchase_order))
if self.user_remark:
r.append(_("Note: {0}").format(self.user_remark))
if r:
self.remark = ("\n").join(r)
else:
frappe.msgprint(_("User Remarks is mandatory"), raise_exception=frappe.MandatoryError)
self.remark = ("\n").join(r) #User Remarks is not mandatory
def set_aging_date(self):
if self.is_opening != 'Yes':
@@ -186,71 +285,38 @@ class JournalVoucher(AccountsController):
def set_print_format_fields(self):
for d in self.get('entries'):
result = frappe.db.get_value("Account", d.account,
["account_type", "master_type"])
acc = frappe.db.get_value("Account", d.account, ["account_type", "master_type"], as_dict=1)
if not result:
continue
if not acc: continue
account_type, master_type = result
if master_type in ['Supplier', 'Customer']:
if acc.master_type in ['Supplier', 'Customer']:
if not self.pay_to_recd_from:
self.pay_to_recd_from = frappe.db.get_value(master_type,
' - '.join(d.account.split(' - ')[:-1]),
master_type == 'Customer' and 'customer_name' or 'supplier_name')
self.pay_to_recd_from = frappe.db.get_value(acc.master_type, ' - '.join(d.account.split(' - ')[:-1]),
acc.master_type == 'Customer' and 'customer_name' or 'supplier_name')
if self.voucher_type in ["Credit Note", "Debit Note"]:
self.set_total_amount(d.debit or d.credit)
if account_type in ['Bank', 'Cash']:
company_currency = get_company_currency(self.company)
amt = flt(d.debit) and d.debit or d.credit
self.total_amount = fmt_money(amt, currency=company_currency)
from frappe.utils import money_in_words
self.total_amount_in_words = money_in_words(amt, company_currency)
if acc.account_type in ['Bank', 'Cash']:
self.set_total_amount(d.debit or d.credit)
def check_credit_days(self):
date_diff = 0
def set_total_amount(self, amt):
company_currency = get_company_currency(self.company)
self.total_amount = fmt_money(amt, currency=company_currency)
from frappe.utils import money_in_words
self.total_amount_in_words = money_in_words(amt, company_currency)
def check_reference_date(self):
if self.cheque_date:
date_diff = (getdate(self.cheque_date)-getdate(self.posting_date)).days
for d in self.get("entries"):
due_date = None
if d.against_invoice and flt(d.credit) > 0:
due_date = frappe.db.get_value("Sales Invoice", d.against_invoice, "due_date")
elif d.against_voucher and flt(d.debit) > 0:
due_date = frappe.db.get_value("Purchase Invoice", d.against_voucher, "due_date")
if date_diff <= 0: return
# Get List of Customer Account
acc_list = filter(lambda d: frappe.db.get_value("Account", d.account,
"master_type")=='Customer', self.get('entries'))
for d in acc_list:
credit_days = self.get_credit_days_for(d.account)
# Check credit days
if credit_days > 0 and not self.get_authorized_user() and cint(date_diff) > credit_days:
msgprint(_("Maximum allowed credit is {0} days after posting date").format(credit_days),
raise_exception=1)
def get_credit_days_for(self, ac):
if not self.credit_days_for.has_key(ac):
self.credit_days_for[ac] = cint(frappe.db.get_value("Account", ac, "credit_days"))
if not self.credit_days_for[ac]:
if self.credit_days_global==-1:
self.credit_days_global = cint(frappe.db.get_value("Company",
self.company, "credit_days"))
return self.credit_days_global
else:
return self.credit_days_for[ac]
def get_authorized_user(self):
if self.is_approving_authority==-1:
self.is_approving_authority = 0
# Fetch credit controller role
approving_authority = frappe.db.get_value("Accounts Settings", None,
"credit_controller")
# Check logged-in user is authorized
if approving_authority in frappe.user.get_roles():
self.is_approving_authority = 1
return self.is_approving_authority
if due_date and getdate(self.cheque_date) > getdate(due_date):
msgprint(_("Note: Reference Date {0} is after invoice due date {1}")
.format(formatdate(self.cheque_date), formatdate(due_date)))
def make_gl_entries(self, cancel=0, adv_adj=0):
from erpnext.accounts.general_ledger import make_gl_entries
@@ -264,14 +330,18 @@ class JournalVoucher(AccountsController):
"against": d.against_account,
"debit": flt(d.debit, self.precision("debit", "entries")),
"credit": flt(d.credit, self.precision("credit", "entries")),
"against_voucher_type": ((d.against_voucher and "Purchase Invoice")
or (d.against_invoice and "Sales Invoice")
or (d.against_jv and "Journal Voucher")),
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv,
"against_voucher_type": (("Purchase Invoice" if d.against_voucher else None)
or ("Sales Invoice" if d.against_invoice else None)
or ("Journal Voucher" if d.against_jv else None)
or ("Sales Order" if d.against_sales_order else None)
or ("Purchase Order" if d.against_purchase_order else None)),
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv
or d.against_sales_order or d.against_purchase_order,
"remarks": self.remark,
"cost_center": d.cost_center
})
)
if gl_map:
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj)
@@ -279,7 +349,7 @@ class JournalVoucher(AccountsController):
for d in self.get("entries"):
master_type, master_name = frappe.db.get_value("Account", d.account,
["master_type", "master_name"])
if master_type == "Customer" and master_name:
if master_type == "Customer" and master_name and flt(d.debit) > 0:
super(JournalVoucher, self).check_credit_limit(d.account)
def get_balance(self):
@@ -434,9 +504,10 @@ def get_against_sales_invoice(doctype, txt, searchfield, start, page_len, filter
(filters["account"], "%%%s%%" % txt, start, page_len))
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
from `tabJournal Voucher` jv, `tabJournal Voucher Detail` jv_detail
where jv_detail.parent = jv.name and jv_detail.account = %s and jv.docstatus = 1
return frappe.db.sql("""select distinct jv.name, jv.posting_date, jv.user_remark
from `tabJournal Voucher` jv, `tabJournal Voucher Detail` jvd
where jvd.parent = jv.name and jvd.account = %s and jv.docstatus = 1
and (ifnull(jvd.against_invoice, '') = '' and ifnull(jvd.against_voucher, '') = '' and ifnull(jvd.against_jv, '') = '' )
and jv.%s like %s order by jv.name desc limit %s, %s""" %
("%s", searchfield, "%s", "%s", "%s"),
(filters["account"], "%%%s%%" % txt, start, page_len))

View File

@@ -1,41 +1,88 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import frappe
import unittest, frappe
from frappe.utils import flt
class TestJournalVoucher(unittest.TestCase):
def test_journal_voucher_with_against_jv(self):
self.clear_account_balance()
jv_invoice = frappe.copy_doc(test_records[2])
jv_invoice.insert()
jv_invoice.submit()
base_jv = frappe.copy_doc(test_records[0])
self.jv_against_voucher_testcase(base_jv, jv_invoice)
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s""",
("_Test Customer - _TC", jv_invoice.name)))
def test_jv_against_sales_order(self):
from erpnext.selling.doctype.sales_order.test_sales_order \
import test_records as so_test_records
sales_order = frappe.copy_doc(so_test_records[0])
base_jv = frappe.copy_doc(test_records[0])
self.jv_against_voucher_testcase(base_jv, sales_order)
def test_jv_against_purchase_order(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order \
import test_records as po_test_records
purchase_order = frappe.copy_doc(po_test_records[0])
base_jv = frappe.copy_doc(test_records[1])
self.jv_against_voucher_testcase(base_jv, purchase_order)
def jv_against_voucher_testcase(self, base_jv, test_voucher):
dr_or_cr = "credit" if test_voucher.doctype in ["Sales Order", "Journal Voucher"] else "debit"
field_dict = {'Journal Voucher': "against_jv",
'Sales Order': "against_sales_order",
'Purchase Order': "against_purchase_order"
}
self.clear_account_balance()
test_voucher.insert()
test_voucher.submit()
if test_voucher.doctype == "Journal Voucher":
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s""",
("_Test Customer - _TC", test_voucher.name)))
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (test_voucher.name)))
jv_payment = frappe.copy_doc(test_records[0])
jv_payment.get("entries")[0].against_jv = jv_invoice.name
jv_payment.insert()
jv_payment.submit()
base_jv.get("entries")[0].is_advance = "Yes" if (test_voucher.doctype in ["Sales Order", "Purchase Order"]) else "No"
base_jv.get("entries")[0].set(field_dict.get(test_voucher.doctype), test_voucher.name)
base_jv.insert()
base_jv.submit()
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (submitted_voucher.name)))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s and credit=400""", jv_invoice.name))
where %s=%s and %s=400""" % (field_dict.get(submitted_voucher.doctype), '%s', dr_or_cr), (submitted_voucher.name)))
# cancel jv_invoice
jv_invoice.cancel()
if base_jv.get("entries")[0].is_advance == "Yes":
self.advance_paid_testcase(base_jv, submitted_voucher, dr_or_cr)
self.cancel_against_voucher_testcase(submitted_voucher)
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
def advance_paid_testcase(self, base_jv, test_voucher, dr_or_cr):
#Test advance paid field
advance_paid = frappe.db.sql("""select advance_paid from `tab%s`
where name=%s""" % (test_voucher.doctype, '%s'), (test_voucher.name))
payment_against_order = base_jv.get("entries")[0].get(dr_or_cr)
self.assertTrue(flt(advance_paid[0][0]) == flt(payment_against_order))
def cancel_against_voucher_testcase(self, test_voucher):
if test_voucher.doctype == "Journal Voucher":
# if test_voucher is a Journal Voucher, test cancellation of test_voucher
test_voucher.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", test_voucher.name))
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
self.assertRaises(frappe.LinkExistsError, submitted_voucher.cancel)
def test_jv_against_stock_account(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory

View File

@@ -117,11 +117,6 @@
"print_hide": 0,
"search_index": 1
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "against_jv",
"fieldtype": "Link",
@@ -135,6 +130,25 @@
"print_hide": 0,
"search_index": 1
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "against_sales_order",
"fieldtype": "Link",
"label": "Against Sales Order",
"options": "Sales Order",
"permlevel": 0
},
{
"fieldname": "against_purchase_order",
"fieldtype": "Link",
"label": "Against Purchase Order",
"options": "Purchase Order",
"permlevel": 0
},
{
"fieldname": "is_advance",
"fieldtype": "Select",
@@ -160,7 +174,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-07-25 03:16:51.149899",
"modified": "2014-08-20 12:19:55.049973",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Voucher Detail",

View File

@@ -19,9 +19,9 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
]
};
}
});
this.frm.set_query('bank_cash_account', function() {
if(!me.frm.doc.company) {
msgprint(__("Please select company first"));
@@ -35,12 +35,8 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
};
}
});
var help_content = '<i class="icon-hand-right"></i> Note:<br>'+
'<ul>If you are unable to match the exact amount, then amend your Journal Voucher and split rows such that payment amount match the invoice amount.</ul>';
this.frm.set_value("reconcile_help", help_content);
},
get_unreconciled_entries: function() {
var me = this;
return this.frm.call({
@@ -48,12 +44,12 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
method: 'get_unreconciled_entries',
callback: function(r, rt) {
var invoices = [];
$.each(me.frm.doc.payment_reconciliation_invoices || [], function(i, row) {
if (row.invoice_number && !inList(invoices, row.invoice_number))
if (row.invoice_number && !inList(invoices, row.invoice_number))
invoices.push(row.invoice_number);
});
frappe.meta.get_docfield("Payment Reconciliation Payment", "invoice_number",
me.frm.doc.name).options = invoices.join("\n");
@@ -79,4 +75,4 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
$.extend(cur_frm.cscript, new erpnext.accounts.PaymentReconciliationController({frm: cur_frm}));
cur_frm.add_fetch('party_account', 'master_type', 'party_type')
cur_frm.add_fetch('party_account', 'master_type', 'party_type')

View File

@@ -118,19 +118,12 @@
"options": "Payment Reconciliation Invoice",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "reconcile_help",
"fieldtype": "Small Text",
"label": "",
"permlevel": 0,
"read_only": 1
}
],
"hide_toolbar": 1,
"icon": "icon-resize-horizontal",
"issingle": 1,
"modified": "2014-07-31 05:43:03.410832",
"modified": "2014-10-16 17:51:44.367107",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation",

View File

@@ -96,13 +96,14 @@ class PaymentReconciliation(Document):
payment_amount = payment_amount[0][0] if payment_amount else 0
if d.invoice_amount > payment_amount:
if d.invoice_amount - payment_amount > 0.005:
non_reconciled_invoices.append({
'voucher_no': d.voucher_no,
'voucher_type': d.voucher_type,
'posting_date': d.posting_date,
'invoice_amount': flt(d.invoice_amount),
'outstanding_amount': d.invoice_amount - payment_amount})
'outstanding_amount': flt(d.invoice_amount - payment_amount, 2)
})
self.add_invoice_entries(non_reconciled_invoices)
@@ -124,7 +125,7 @@ class PaymentReconciliation(Document):
dr_or_cr = "credit" if self.party_type == "Customer" else "debit"
lst = []
for e in self.get('payment_reconciliation_payments'):
if e.invoice_type and e.invoice_number:
if e.invoice_type and e.invoice_number and e.allocated_amount:
lst.append({
'voucher_no' : e.journal_voucher,
'voucher_detail_no' : e.voucher_detail_number,
@@ -134,7 +135,7 @@ class PaymentReconciliation(Document):
'is_advance' : e.is_advance,
'dr_or_cr' : dr_or_cr,
'unadjusted_amt' : flt(e.amount),
'allocated_amt' : flt(e.amount)
'allocated_amt' : flt(e.allocated_amount)
})
if lst:
@@ -162,18 +163,23 @@ class PaymentReconciliation(Document):
invoices_to_reconcile = []
for p in self.get("payment_reconciliation_payments"):
if p.invoice_type and p.invoice_number:
if p.invoice_type and p.invoice_number and p.allocated_amount:
invoices_to_reconcile.append(p.invoice_number)
if p.invoice_number not in unreconciled_invoices.get(p.invoice_type, {}):
frappe.throw(_("{0}: {1} not found in Invoice Details table")
.format(p.invoice_type, p.invoice_number))
if p.amount > unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number):
frappe.throw(_("Row {0}: Payment amount must be less than or equals to invoice outstanding amount. Please refer Note below.").format(p.idx))
if flt(p.allocated_amount) > flt(p.amount):
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to JV amount {2}")
.format(p.idx, p.allocated_amount, p.amount))
if flt(p.allocated_amount) > unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number):
frappe.throw(_("Row {0}: Allocated amount {1} must be less than or equals to invoice outstanding amount {2}")
.format(p.idx, p.allocated_amount, unreconciled_invoices.get(p.invoice_type, {}).get(p.invoice_number)))
if not invoices_to_reconcile:
frappe.throw(_("Please select Invoice Type and Invoice Number in atleast one row"))
frappe.throw(_("Please select Allocated Amount, Invoice Type and Invoice Number in atleast one row"))
def check_condition(self, dr_or_cr):
cond = self.from_date and " and posting_date >= '" + self.from_date + "'" or ""

View File

@@ -53,11 +53,20 @@
"label": "Column Break",
"permlevel": 0
},
{
"fieldname": "allocated_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Allocated amount",
"permlevel": 0,
"precision": "",
"reqd": 1
},
{
"default": "Sales Invoice",
"fieldname": "invoice_type",
"fieldtype": "Select",
"in_list_view": 1,
"in_list_view": 0,
"label": "Invoice Type",
"options": "\nSales Invoice\nPurchase Invoice\nJournal Voucher",
"permlevel": 0,
@@ -95,7 +104,7 @@
}
],
"istable": 1,
"modified": "2014-07-21 16:53:56.206169",
"modified": "2014-10-16 17:40:54.040194",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Reconciliation Payment",

View File

@@ -0,0 +1,214 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// For license information, please see license.txt
frappe.provide("erpnext.payment_tool");
// Help content
frappe.ui.form.on("Payment Tool", "onload", function(frm) {
frm.set_value("make_jv_help", '<i class="icon-hand-right"></i> '
+ __("Note: If payment is not made against any reference, make Journal Voucher manually."));
frm.set_query("payment_account", function() {
return {
filters: [
['Account', 'account_type', 'in', 'Bank, Cash'],
['Account', 'group_or_ledger', '=', 'Ledger'],
['Account', 'company', '=', frm.doc.company]
]
}
});
frm.set_query("against_voucher_type", "payment_tool_details", function() {
return {
filters: {"name": ["in", ["Sales Invoice", "Purchase Invoice", "Journal Voucher", "Sales Order", "Purchase Order"]]}
};
});
});
frappe.ui.form.on("Payment Tool", "refresh", function(frm) {
frappe.ui.form.trigger("Payment Tool", "party_type");
});
frappe.ui.form.on("Payment Tool", "party_type", function(frm) {
frm.toggle_reqd("customer", frm.doc.party_type == "Customer");
frm.toggle_reqd("supplier", frm.doc.party_type == "Supplier");
});
frappe.ui.form.on("Payment Tool", "company", function(frm) {
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
frappe.ui.form.on("Payment Tool", "received_or_paid", function(frm) {
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
// Set party account name
frappe.ui.form.on("Payment Tool", "customer", function(frm) {
erpnext.payment_tool.set_party_account(frm);
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
frappe.ui.form.on("Payment Tool", "supplier", function(frm) {
erpnext.payment_tool.set_party_account(frm);
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
erpnext.payment_tool.check_mandatory_to_set_button = function(frm) {
if (frm.doc.company && frm.doc.party_type && frm.doc.received_or_paid && (frm.doc.customer || frm.doc.supplier)) {
frm.fields_dict.get_outstanding_vouchers.$input.addClass("btn-primary");
}
}
//Set Button color
erpnext.payment_tool.set_party_account = function(frm) {
if(frm.doc.party_type == "Customer") {
var party_name = frm.doc.customer;
} else {
var party_name = frm.doc.supplier;
}
return frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_party_account',
args: {
party_type: frm.doc.party_type,
party_name: party_name
},
callback: function(r, rt) {
if(!r.exc) {
frm.set_value("party_account", r.message);
}
}
});
}
// Get outstanding vouchers
frappe.ui.form.on("Payment Tool", "get_outstanding_vouchers", function(frm) {
erpnext.payment_tool.check_mandatory_to_fetch(frm.doc);
frm.set_value("payment_tool_details", []);
return frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_outstanding_vouchers',
args: {
args: {
"company": frm.doc.company,
"party_type": frm.doc.party_type,
"received_or_paid": frm.doc.received_or_paid,
"party_name": frm.doc.party_type == "Customer" ? frm.doc.customer : frm.doc.supplier,
"party_account": frm.doc.party_account
}
},
callback: function(r, rt) {
if(r.message) {
frm.fields_dict.get_outstanding_vouchers.$input.removeClass("btn-primary");
frm.fields_dict.make_journal_voucher.$input.addClass("btn-primary");
frappe.model.clear_table(frm.doc, "payment_tool_details");
$.each(r.message, function(i, d) {
var invoice_detail = frappe.model.add_child(frm.doc, "Payment Tool Detail", "payment_tool_details");
invoice_detail.against_voucher_type = d.voucher_type;
invoice_detail.against_voucher_no = d.voucher_no;
invoice_detail.total_amount = d.invoice_amount;
invoice_detail.outstanding_amount = d.outstanding_amount;
});
}
refresh_field("payment_tool_details");
erpnext.payment_tool.set_total_payment_amount(frm);
}
});
});
// validate against_voucher_type
frappe.ui.form.on("Payment Tool Detail", "against_voucher_type", function(frm) {
erpnext.payment_tool.validate_against_voucher(frm);
});
erpnext.payment_tool.validate_against_voucher = function(frm) {
$.each(frm.doc.payment_tool_details || [], function(i, row) {
if(frm.doc.party_type=="Customer"
&& !in_list(["Sales Order", "Sales Invoice", "Journal Voucher"], row.against_voucher_type)) {
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
frappe.throw(__("Against Voucher Type must be one of Sales Order, Sales Invoice or Journal Voucher"))
}
if(frm.doc.party_type=="Supplier"
&& !in_list(["Purchase Order", "Purchase Invoice", "Journal Voucher"], row.against_voucher_type)) {
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
frappe.throw(__("Against Voucher Type must be one of Purchase Order, Purchase Invoice or Journal Voucher"))
}
});
}
// validate against_voucher_type
frappe.ui.form.on("Payment Tool Detail", "against_voucher_no", function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_against_voucher_amount',
args: {
"against_voucher_type": row.against_voucher_type,
"against_voucher_no": row.against_voucher_no
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frappe.model.set_value(cdt, cdn, k, v);
});
}
}
});
});
// Set total payment amount
frappe.ui.form.on("Payment Tool Detail", "payment_amount", function(frm) {
erpnext.payment_tool.set_total_payment_amount(frm);
});
frappe.ui.form.on("Payment Tool Detail", "payment_tool_details_remove", function(frm) {
erpnext.payment_tool.set_total_payment_amount(frm);
});
erpnext.payment_tool.set_total_payment_amount = function(frm) {
var total_amount = 0.00;
$.each(frm.doc.payment_tool_details || [], function(i, row) {
if (row.payment_amount && (row.payment_amount <= row.outstanding_amount)) {
total_amount = total_amount + row.payment_amount;
} else {
if(row.payment_amount < 0)
msgprint(__("Row {0}: Payment amount can not be negative", [row.idx]));
else if(row.payment_amount >= row.outstanding_amount)
msgprint(__("Row {0}: Payment Amount cannot be greater than Outstanding Amount", [__(row.idx)]));
frappe.model.set_value(row.doctype, row.name, "payment_amount", 0.0);
}
});
frm.set_value("total_payment_amount", total_amount);
}
// Make Journal voucher
frappe.ui.form.on("Payment Tool", "make_journal_voucher", function(frm) {
erpnext.payment_tool.check_mandatory_to_fetch(frm.doc);
return frappe.call({
method: 'make_journal_voucher',
doc: frm.doc,
callback: function(r) {
frm.fields_dict.make_journal_voucher.$input.addClass("btn-primary");
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
});
});
erpnext.payment_tool.check_mandatory_to_fetch = function(doc) {
var check_fields = [
['Company', doc.company],
['Party Type', doc.party_type],
['Received Or Paid', doc.received_or_paid],
['Customer / Supplier', doc.party_type == "Customer" ? doc.customer : doc.supplier]
];
$.each(check_fields, function(i, v) {
if(!v[1]) frappe.throw(__("Please select {0} first", [v[0]]));
});
}

View File

@@ -0,0 +1,381 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2014-07-23 15:12:27.746665",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"fieldname": "sec_break1",
"fieldtype": "Section Break",
"label": "Party Details",
"permlevel": 0
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"permlevel": 0,
"reqd": 1
},
{
"allow_on_submit": 0,
"default": "Customer",
"fieldname": "party_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Party Type",
"no_copy": 0,
"options": "Customer\nSupplier",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.party_type == 'Customer')",
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Customer",
"no_copy": 0,
"options": "Customer",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.party_type == 'Supplier')",
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Supplier",
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "party_account",
"fieldtype": "Link",
"hidden": 1,
"label": "Party Account",
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"read_only": 1
},
{
"allow_on_submit": 0,
"fieldname": "received_or_paid",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Received Or Paid",
"no_copy": 0,
"options": "Received\nPaid",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "get_outstanding_vouchers",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Get Outstanding Vouchers",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Column Break 1",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_mode",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Mode",
"no_copy": 0,
"options": "Mode of Payment",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Account",
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "reference_no",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference No",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "reference_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Date",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "sec_break3",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Against Voucher",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_tool_details",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Tool Details",
"no_copy": 0,
"options": "Payment Tool Detail",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "section_break_19",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "total_payment_amount",
"fieldtype": "Currency",
"label": "Total Payment Amount",
"permlevel": 0,
"read_only": 1
},
{
"allow_on_submit": 0,
"fieldname": "make_journal_voucher",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Make Journal Voucher",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "data_22",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "section_break_21",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "make_jv_help",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 1,
"icon": "icon-magic",
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2014-09-12 04:43:05.963218",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts Manager",
"set_user_permissions": 0,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts User",
"set_user_permissions": 0,
"submit": 0,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -0,0 +1,119 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from frappe.model.document import Document
import json
class PaymentTool(Document):
def make_journal_voucher(self):
from erpnext.accounts.utils import get_balance_on
total_payment_amount = 0.00
invoice_voucher_type = {
'Sales Invoice': 'against_invoice',
'Purchase Invoice': 'against_voucher',
'Journal Voucher': 'against_jv',
'Sales Order': 'against_sales_order',
'Purchase Order': 'against_purchase_order',
}
jv = frappe.new_doc('Journal Voucher')
jv.voucher_type = 'Journal Entry'
jv.company = self.company
jv.cheque_no = self.reference_no
jv.cheque_date = self.reference_date
if not self.total_payment_amount:
frappe.throw(_("Please enter Payment Amount in atleast one row"))
for v in self.get("payment_tool_details"):
if not frappe.db.get_value(v.against_voucher_type, {"name": v.against_voucher_no}):
frappe.throw(_("Row {0}: {1} is not a valid {2}").format(v.idx, v.against_voucher_no,
v.against_voucher_type))
if v.payment_amount:
d1 = jv.append("entries")
d1.account = self.party_account
d1.balance = get_balance_on(self.party_account)
d1.set("debit" if self.received_or_paid=="Paid" else "credit", flt(v.payment_amount))
d1.set(invoice_voucher_type.get(v.against_voucher_type), v.against_voucher_no)
d1.set('is_advance', 'Yes' if v.against_voucher_type in ['Sales Order', 'Purchase Order'] else 'No')
total_payment_amount = flt(total_payment_amount) + flt(d1.debit) - flt(d1.credit)
d2 = jv.append("entries")
d2.account = self.payment_account
d2.set('debit' if total_payment_amount < 0 else 'credit', abs(total_payment_amount))
if self.payment_account:
d2.balance = get_balance_on(self.payment_account)
return jv.as_dict()
@frappe.whitelist()
def get_party_account(party_type, party_name):
return frappe.db.get_value("Account", {"master_type": party_type, "master_name": party_name})
@frappe.whitelist()
def get_outstanding_vouchers(args):
from erpnext.accounts.utils import get_outstanding_invoices
if not frappe.has_permission("Payment Tool"):
frappe.throw(_("No permission to use Payment Tool"), frappe.PermissionError)
args = json.loads(args)
if args.get("party_type") == "Customer" and args.get("received_or_paid") == "Received":
amount_query = "ifnull(debit, 0) - ifnull(credit, 0)"
elif args.get("party_type") == "Supplier" and args.get("received_or_paid") == "Paid":
amount_query = "ifnull(credit, 0) - ifnull(debit, 0)"
else:
frappe.throw(_("Please enter the Against Vouchers manually"))
# Get all outstanding sales /purchase invoices
outstanding_invoices = get_outstanding_invoices(amount_query, args.get("party_account"))
# Get all SO / PO which are not fully billed or aginst which full advance not paid
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party_name"))
return outstanding_invoices + orders_to_be_billed
def get_orders_to_be_billed(party_type, party_name):
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
orders = frappe.db.sql("""
select
name as voucher_no,
ifnull(grand_total, 0) as invoice_amount,
(ifnull(grand_total, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
transaction_date as posting_date
from
`tab%s`
where
%s = %s
and docstatus = 1
and ifnull(status, "") != "Stopped"
and ifnull(grand_total, 0) > ifnull(advance_paid, 0)
and abs(100 - ifnull(per_billed, 0)) > 0.01
""" % (voucher_type, 'customer' if party_type == "Customer" else 'supplier', '%s'),
party_name, as_dict = True)
order_list = []
for d in orders:
d["voucher_type"] = voucher_type
order_list.append(d)
return order_list
@frappe.whitelist()
def get_against_voucher_amount(against_voucher_type, against_voucher_no):
if against_voucher_type in ["Sales Order", "Purchase Order"]:
select_cond = "grand_total as total_amount, ifnull(grand_total, 0) - ifnull(advance_paid, 0) as outstanding_amount"
elif against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
select_cond = "grand_total as total_amount, outstanding_amount"
elif against_voucher_type == "Journal Voucher":
select_cond = "total_debit as total_amount"
details = frappe.db.sql("""select {0} from `tab{1}` where name = %s"""
.format(select_cond, against_voucher_type), against_voucher_no, as_dict=1)
return details[0] if details else {}

View File

@@ -0,0 +1,195 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest, frappe, json
from frappe.utils import flt
test_dependencies = ["Item"]
class TestPaymentTool(unittest.TestCase):
def test_make_journal_voucher(self):
from erpnext.accounts.doctype.journal_voucher.test_journal_voucher \
import test_records as jv_test_records
from erpnext.selling.doctype.sales_order.test_sales_order \
import test_records as so_test_records
from erpnext.buying.doctype.purchase_order.test_purchase_order \
import test_records as po_test_records
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \
import test_records as si_test_records
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice \
import test_records as pi_test_records
self.clear_table_entries()
base_customer_jv = self.create_against_jv(jv_test_records[2], { "account": "_Test Customer 3 - _TC"})
base_supplier_jv = self.create_against_jv(jv_test_records[1], { "account": "_Test Supplier 1 - _TC"})
#Create SO with partial outstanding
so1 = self.create_voucher(so_test_records[0], {
"customer": "_Test Customer 3"
})
jv_against_so1 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_sales_order": so1.name,
"is_advance": "Yes"
})
#Create SO with no outstanding
so2 = self.create_voucher(so_test_records[0], {
"customer": "_Test Customer 3"
})
jv_against_so2 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_sales_order": so2.name,
"credit": 1000,
"is_advance": "Yes"
})
po = self.create_voucher(po_test_records[1], {
"supplier": "_Test Supplier 1"
})
#Create SI with partial outstanding
si1 = self.create_voucher(si_test_records[0], {
"customer": "_Test Customer 3",
"debit_to": "_Test Customer 3 - _TC"
})
jv_against_si1 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_invoice": si1.name
})
#Create SI with no outstanding
si2 = self.create_voucher(si_test_records[0], {
"customer": "_Test Customer 3",
"debit_to": "_Test Customer 3 - _TC"
})
jv_against_si2 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_invoice": si2.name,
"credit": 561.80
})
pi = self.create_voucher(pi_test_records[0], {
"supplier": "_Test Supplier 1",
"credit_to": "_Test Supplier 1 - _TC"
})
#Create a dict containing properties and expected values
expected_outstanding = {
"Journal Voucher" : [base_customer_jv.name, 400.00],
"Sales Invoice" : [si1.name, 161.80],
"Purchase Invoice" : [pi.name, 1512.30],
"Sales Order" : [so1.name, 600.00],
"Purchase Order" : [po.name, 5000.00]
}
args = {
"company": "_Test Company",
"party_type": "Customer",
"received_or_paid": "Received",
"customer": "_Test Customer",
"party_account": "_Test Customer 3 - _TC",
"payment_mode": "Cheque",
"payment_account": "_Test Account Bank Account - _TC",
"reference_no": "123456",
"reference_date": "2013-02-14"
}
self.make_voucher_for_party(args, expected_outstanding)
args.update({
"party_type": "Supplier",
"received_or_paid": "Paid",
"supplier": "_Test Supplier 1",
"party_account": "_Test Supplier 1 - _TC"
})
expected_outstanding["Journal Voucher"] = [base_supplier_jv.name, 400.00]
self.make_voucher_for_party(args, expected_outstanding)
def create_voucher(self, test_record, args):
doc = frappe.copy_doc(test_record)
doc.update(args)
doc.insert()
doc.submit()
return doc
def create_against_jv(self, test_record, args):
jv = frappe.copy_doc(test_record)
jv.get("entries")[0].update(args)
if args.get("debit"):
jv.get("entries")[1].credit = args["debit"]
elif args.get("credit"):
jv.get("entries")[1].debit = args["credit"]
jv.insert()
jv.submit()
return jv
def make_voucher_for_party(self, args, expected_outstanding):
#Make Journal Voucher for Party
payment_tool_doc = frappe.new_doc("Payment Tool")
for k, v in args.items():
payment_tool_doc.set(k, v)
self.check_outstanding_vouchers(payment_tool_doc, args, expected_outstanding)
def check_outstanding_vouchers(self, doc, args, expected_outstanding):
from erpnext.accounts.doctype.payment_tool.payment_tool import get_outstanding_vouchers
outstanding_entries = get_outstanding_vouchers(json.dumps(args))
for d in outstanding_entries:
self.assertEquals(flt(d.get("outstanding_amount"), 2), expected_outstanding.get(d.get("voucher_type"))[1])
self.check_jv_entries(doc, outstanding_entries, expected_outstanding)
def check_jv_entries(self, paytool, outstanding_entries, expected_outstanding):
for e in outstanding_entries:
d1 = paytool.append("payment_tool_details")
d1.against_voucher_type = e.get("voucher_type")
d1.against_voucher_no = e.get("voucher_no")
d1.total_amount = e.get("invoice_amount")
d1.outstanding_amount = e.get("outstanding_amount")
d1.payment_amount = 100.00
paytool.total_payment_amount = 300
new_jv = paytool.make_journal_voucher()
#Create a list of expected values as [party account, payment against, against_jv, against_invoice,
#against_voucher, against_sales_order, against_purchase_order]
expected_values = [
[paytool.party_account, 100.00, expected_outstanding.get("Journal Voucher")[0], None, None, None, None],
[paytool.party_account, 100.00, None, expected_outstanding.get("Sales Invoice")[0], None, None, None],
[paytool.party_account, 100.00, None, None, expected_outstanding.get("Purchase Invoice")[0], None, None],
[paytool.party_account, 100.00, None, None, None, expected_outstanding.get("Sales Order")[0], None],
[paytool.party_account, 100.00, None, None, None, None, expected_outstanding.get("Purchase Order")[0]]
]
for jv_entry in new_jv.get("entries"):
if paytool.party_account == jv_entry.get("account"):
row = [
jv_entry.get("account"),
jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"),
jv_entry.get("against_jv"),
jv_entry.get("against_invoice"),
jv_entry.get("against_voucher"),
jv_entry.get("against_sales_order"),
jv_entry.get("against_purchase_order"),
]
self.assertTrue(row in expected_values)
self.assertEquals(new_jv.get("cheque_no"), paytool.reference_no)
self.assertEquals(new_jv.get("cheque_date"), paytool.reference_date)
def clear_table_entries(self):
frappe.db.sql("""delete from `tabGL Entry` where (account = "_Test Customer 3 - _TC" or account = "_Test Supplier 1 - _TC")""")
frappe.db.sql("""delete from `tabSales Order` where customer_name = "_Test Customer 3" """)
frappe.db.sql("""delete from `tabPurchase Order` where supplier_name = "_Test Supplier 1" """)

View File

@@ -0,0 +1,130 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2014-08-11 14:27:54.463897",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "against_voucher_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Against Voucher Type",
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_width": "",
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"width": ""
},
{
"allow_on_submit": 0,
"fieldname": "against_voucher_no",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Against Voucher No",
"no_copy": 0,
"options": "against_voucher_type",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "total_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Total Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "outstanding_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Outstanding Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Payment Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2014-09-11 08:55:34.384017",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool Detail",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@@ -1,10 +1,9 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class ContactControl(Document):
pass
class PaymentToolDetail(Document):
pass

View File

@@ -171,6 +171,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
@@ -192,6 +193,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"in_filter": 0,
@@ -205,7 +207,7 @@
],
"icon": "icon-cog",
"idx": 1,
"modified": "2014-06-23 16:40:59.510132",
"modified": "2014-09-09 05:35:31.969193",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Setting",

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('POS Setting')
class TestPOSSetting(unittest.TestCase):
pass

View File

@@ -0,0 +1 @@
[]

View File

@@ -232,7 +232,6 @@ cur_frm.fields_dict['entries'].grid.get_field('project_name').get_query = functi
}
}
cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
if(doc.select_print_heading){
// print heading

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,10 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, formatdate
from frappe.utils import cint, cstr, formatdate, flt
from frappe import msgprint, _, throw
from erpnext.setup.utils import get_company_currency
import frappe.defaults
from erpnext.controllers.buying_controller import BuyingController
@@ -49,6 +48,7 @@ class PurchaseInvoice(BuyingController):
self.check_conversion_rate()
self.validate_credit_acc()
self.clear_unallocated_advances("Purchase Invoice Advance", "advance_allocation_details")
self.validate_advance_jv("advance_allocation_details", "purchase_order")
self.check_for_acc_head_of_supplier()
self.check_for_stopped_status()
self.validate_with_previous_doc()
@@ -80,7 +80,7 @@ class PurchaseInvoice(BuyingController):
def get_advances(self):
super(PurchaseInvoice, self).get_advances(self.credit_to,
"Purchase Invoice Advance", "advance_allocation_details", "debit")
"Purchase Invoice Advance", "advance_allocation_details", "debit", "purchase_order")
def check_active_purchase_items(self):
for d in self.get('entries'):
@@ -249,6 +249,8 @@ class PurchaseInvoice(BuyingController):
reconcile_against_document(lst)
def on_submit(self):
super(PurchaseInvoice, self).on_submit()
self.check_prev_docstatus()
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
@@ -403,7 +405,7 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
# Hence the first condition is an "OR"
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
or tabAccount.account_type = "Expense Account")
or tabAccount.account_type in ("Expense Account", "Fixed Asset"))
and tabAccount.group_or_ledger="Ledger"
and tabAccount.docstatus!=2
and ifnull(tabAccount.master_type, "")=""

View File

@@ -231,4 +231,8 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_voucher=%s""", pi.name))
def test_recurring_invoice(self):
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
test_recurring_document(self, test_records)
test_records = frappe.get_test_records('Purchase Invoice')

View File

@@ -399,7 +399,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.027289",
"modified": "2014-09-09 05:35:35.712453",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@@ -114,7 +114,7 @@ erpnext.POS = Class.extend({
});
this.wrapper.find('input.discount-amount').on("change", function() {
frappe.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", this.value);
frappe.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", flt(this.value));
});
this.call_function("remove-items", function() {me.remove_selected_items();});
@@ -233,6 +233,11 @@ erpnext.POS = Class.extend({
},
make_item_list: function() {
var me = this;
if(!this.price_list) {
msgprint(__("Price List not found or disabled"));
return;
}
me.item_timeout = null;
frappe.call({
method: 'erpnext.accounts.doctype.sales_invoice.pos.get_items',
@@ -487,7 +492,7 @@ erpnext.POS = Class.extend({
});
me.refresh_delete_btn();
if(me.frm.doc[this.party]) {
if(me.frm.doc[this.party.toLowerCase()]) {
this.barcode.$input.focus();
} else {
this.party_field.$input.focus();

View File

@@ -225,8 +225,7 @@ $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_
// Hide Fields
// ------------
cur_frm.cscript.hide_fields = function(doc) {
par_flds = ['project_name', 'due_date', 'is_opening', 'source', 'total_advance', 'gross_profit',
'gross_profit_percent', 'get_advances_received',
par_flds = ['project_name', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances_received',
'advance_adjustment_details', 'sales_partner', 'commission_rate',
'total_commission', 'advances', 'from_date', 'to_date'];
@@ -399,37 +398,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
})
}
cur_frm.cscript.is_recurring = function(doc, dt, dn) {
// set default values for recurring invoices
if(doc.is_recurring) {
var owner_email = doc.owner=="Administrator"
? frappe.user_info("Administrator").email
: doc.owner;
doc.notification_email_address = $.map([cstr(owner_email),
cstr(doc.contact_email)], function(v) { return v || null; }).join(", ");
doc.repeat_on_day_of_month = frappe.datetime.str_to_obj(doc.posting_date).getDate();
}
refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
}
cur_frm.cscript.from_date = function(doc, dt, dn) {
// set to_date
if(doc.from_date) {
var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
'Yearly': 12};
var months = recurring_type_map[doc.recurring_type];
if(months) {
var to_date = frappe.datetime.add_months(doc.from_date,
months);
doc.to_date = frappe.datetime.add_days(to_date, -1);
refresh_field('to_date');
}
}
}
cur_frm.cscript.send_sms = function() {
frappe.require("assets/erpnext/js/sms_manager.js");
var sms_man = new SMSManager(cur_frm.doc);

View File

@@ -1,5 +1,4 @@
{
"allow_attach": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:05",
@@ -170,28 +169,25 @@
"search_index": 0
},
{
"allow_on_submit": 1,
"depends_on": "",
"description": "Start date of current invoice's period",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From",
"no_copy": 1,
"fieldname": "shipping_address_name",
"fieldtype": "Link",
"hidden": 1,
"in_filter": 1,
"label": "Shipping Address Name",
"options": "Address",
"permlevel": 0,
"print_hide": 0,
"read_only": 0
"precision": "",
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "",
"description": "End date of current invoice's period",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To",
"no_copy": 1,
"fieldname": "shipping_address",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Shipping Address",
"permlevel": 0,
"print_hide": 0,
"read_only": 0
"precision": "",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "currency_section",
@@ -426,6 +422,15 @@
"fieldtype": "Section Break",
"permlevel": 0
},
{
"fieldname": "other_charges_total_export",
"fieldtype": "Currency",
"label": "Total Taxes and Charges",
"options": "currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "other_charges_total",
"fieldtype": "Currency",
@@ -442,23 +447,24 @@
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "other_charges_total_export",
"fieldtype": "Currency",
"label": "Total Taxes and Charges",
"options": "currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount",
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0
},
{
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount (Company Currency)",
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "totals",
"fieldtype": "Section Break",
@@ -572,27 +578,6 @@
"print_hide": 0,
"read_only": 1
},
{
"fieldname": "gross_profit",
"fieldtype": "Currency",
"label": "Gross Profit",
"oldfieldname": "gross_profit",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "gross_profit_percent",
"fieldtype": "Float",
"label": "Gross Profit (%)",
"oldfieldname": "gross_profit_percent",
"oldfieldtype": "Currency",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "advances",
"fieldtype": "Section Break",
@@ -1109,6 +1094,30 @@
"print_hide": 1,
"read_only": 0
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "Start date of current invoice's period",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 0,
"read_only": 0
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "End date of current invoice's period",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 0,
"read_only": 0
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
@@ -1121,17 +1130,6 @@
"print_hide": 1,
"read_only": 0
},
{
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which next invoice will be generated. It is generated on submit.\n",
"fieldname": "next_date",
"fieldtype": "Date",
"label": "Next Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
@@ -1153,6 +1151,17 @@
"read_only": 0,
"width": "50%"
},
{
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which next invoice will be generated. It is generated on submit.\n",
"fieldname": "next_date",
"fieldtype": "Date",
"label": "Next Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "eval:doc.is_recurring==1",
"description": "The unique id for tracking all recurring invoices.\u00a0It is generated on submit.",
@@ -1193,7 +1202,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-28 11:21:00.726344",
"modified": "2015-01-12 17:34:36.353241",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@@ -4,18 +4,12 @@
from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
get_first_day, get_last_day
from frappe.model.naming import make_autoname
from frappe.utils import cint, cstr, flt
from frappe import _, msgprint, throw
from erpnext.accounts.party import get_party_account, get_due_date
from erpnext.controllers.stock_controller import update_gl_entries_after
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.recurring_document import *
from erpnext.controllers.selling_controller import SellingController
form_grid_templates = {
@@ -56,6 +50,7 @@ class SalesInvoice(SellingController):
self.validate_debit_acc()
self.validate_fixed_asset_account()
self.clear_unallocated_advances("Sales Invoice Advance", "advance_adjustment_details")
self.validate_advance_jv("advance_adjustment_details", "sales_order")
self.add_remarks()
if cint(self.is_pos):
@@ -71,15 +66,18 @@ class SalesInvoice(SellingController):
self.is_opening = 'No'
self.set_aging_date()
frappe.get_doc("Account", self.debit_to).validate_due_date(self.posting_date, self.due_date)
self.set_against_income_account()
self.validate_c_form()
self.validate_time_logs_are_submitted()
validate_recurring_document(self)
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
"delivery_note_details")
def on_submit(self):
super(SalesInvoice, self).on_submit()
if cint(self.update_stock) == 1:
self.update_stock_ledger()
else:
@@ -101,9 +99,7 @@ class SalesInvoice(SellingController):
if not cint(self.is_pos) == 1:
self.update_against_document_in_jv()
self.update_c_form()
self.update_time_log_batch(self.name)
convert_to_recurring(self, "RECINV.#####", self.posting_date)
def before_cancel(self):
self.update_time_log_batch(None)
@@ -120,6 +116,7 @@ class SalesInvoice(SellingController):
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.validate_c_form_on_cancel()
self.make_gl_entries_on_cancel()
@@ -143,10 +140,6 @@ class SalesInvoice(SellingController):
'overflow_type': 'delivery'
})
def on_update_after_submit(self):
validate_recurring_document(self)
convert_to_recurring(self, "RECINV.#####", self.posting_date)
def get_portal_page(self):
return "invoice" if self.docstatus==1 else None
@@ -216,7 +209,7 @@ class SalesInvoice(SellingController):
def get_advances(self):
super(SalesInvoice, self).get_advances(self.debit_to,
"Sales Invoice Advance", "advance_adjustment_details", "credit")
"Sales Invoice Advance", "advance_adjustment_details", "credit", "sales_order")
def get_company_abbr(self):
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
@@ -376,6 +369,12 @@ class SalesInvoice(SellingController):
frappe.db.set(self, 'c_form_no', '')
def validate_c_form_on_cancel(self):
""" Display message if C-Form no exists on cancellation of Sales Invoice"""
if self.c_form_applicable == 'Yes' and self.c_form_no:
msgprint(_("Please remove this Invoice {0} from C-Form {1}")
.format(self.name, self.c_form_no), raise_exception = 1)
def update_current_stock(self):
for d in self.get('entries'):
if d.item_code and d.warehouse:
@@ -474,9 +473,8 @@ class SalesInvoice(SellingController):
if repost_future_gle and cint(self.update_stock) \
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
items, warehouse_account = self.get_items_and_warehouse_accounts()
update_gl_entries_after(self.posting_date, self.posting_time,
warehouse_account, items)
items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
def get_gl_entries(self, warehouse_account=None):
from erpnext.accounts.general_ledger import merge_similar_entries
@@ -584,14 +582,6 @@ class SalesInvoice(SellingController):
})
)
def update_c_form(self):
"""Update amended id in C-form"""
if self.c_form_no and self.amended_from:
frappe.db.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""",
(self.name, self.amended_from, self.c_form_no))
@frappe.whitelist()
def get_bank_cash_account(mode_of_payment):
val = frappe.db.get_value("Mode of Payment", mode_of_payment, "default_account")

View File

@@ -439,7 +439,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.382092",
"modified": "2014-09-09 05:35:36.019576",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@@ -1,155 +1,156 @@
{
"autoname": "INVTD.######",
"creation": "2013-04-24 11:39:32",
"docstatus": 0,
"doctype": "DocType",
"autoname": "INVTD.######",
"creation": "2013-04-24 11:39:32",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "charge_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Type",
"oldfieldname": "charge_type",
"oldfieldtype": "Select",
"options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total",
"permlevel": 0,
"fieldname": "charge_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Type",
"oldfieldname": "charge_type",
"oldfieldtype": "Select",
"options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total",
"permlevel": 0,
"reqd": 1
},
},
{
"depends_on": "eval:[\"On Previous Row Amount\", \"On Previous Row Total\"].indexOf(doc.charge_type)!==-1",
"fieldname": "row_id",
"fieldtype": "Data",
"hidden": 0,
"label": "Reference Row #",
"oldfieldname": "row_id",
"oldfieldtype": "Data",
"depends_on": "eval:[\"On Previous Row Amount\", \"On Previous Row Total\"].indexOf(doc.charge_type)!==-1",
"fieldname": "row_id",
"fieldtype": "Data",
"hidden": 0,
"label": "Reference Row #",
"oldfieldname": "row_id",
"oldfieldtype": "Data",
"permlevel": 0
},
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_width": "300px",
"reqd": 1,
"fieldname": "description",
"fieldtype": "Small Text",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Small Text",
"permlevel": 0,
"print_width": "300px",
"reqd": 1,
"width": "300px"
},
},
{
"fieldname": "col_break_1",
"fieldtype": "Column Break",
"permlevel": 0,
"fieldname": "col_break_1",
"fieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
},
{
"fieldname": "account_head",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Account Head",
"oldfieldname": "account_head",
"oldfieldtype": "Link",
"options": "Account",
"permlevel": 0,
"reqd": 1,
"fieldname": "account_head",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Account Head",
"oldfieldname": "account_head",
"oldfieldtype": "Link",
"options": "Account",
"permlevel": 0,
"reqd": 1,
"search_index": 1
},
},
{
"default": ":Company",
"fieldname": "cost_center",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Cost Center",
"oldfieldname": "cost_center_other_charges",
"oldfieldtype": "Link",
"options": "Cost Center",
"default": ":Company",
"fieldname": "cost_center",
"fieldtype": "Link",
"in_list_view": 0,
"label": "Cost Center",
"oldfieldname": "cost_center_other_charges",
"oldfieldtype": "Link",
"options": "Cost Center",
"permlevel": 0
},
},
{
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "rate",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "tax_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"oldfieldname": "tax_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"read_only": 1,
"fieldname": "tax_amount",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Amount",
"oldfieldname": "tax_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"read_only": 1,
"reqd": 0
},
},
{
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"oldfieldname": "total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"oldfieldname": "total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"read_only": 1
},
},
{
"allow_on_submit": 0,
"description": "If checked, the tax amount will be considered as already included in the Print Rate / Print Amount",
"fieldname": "included_in_print_rate",
"fieldtype": "Check",
"label": "Is this Tax included in Basic Rate?",
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"print_width": "150px",
"report_hide": 1,
"allow_on_submit": 0,
"description": "If checked, the tax amount will be considered as already included in the Print Rate / Print Amount",
"fieldname": "included_in_print_rate",
"fieldtype": "Check",
"label": "Is this Tax included in Basic Rate?",
"no_copy": 0,
"permlevel": 0,
"print_hide": 1,
"print_width": "150px",
"report_hide": 1,
"width": "150px"
},
},
{
"fieldname": "tax_amount_after_discount_amount",
"fieldtype": "Currency",
"hidden": 1,
"label": "Tax Amount After Discount Amount",
"options": "Company:company:default_currency",
"permlevel": 0,
"depends_on": "eval:parent.discount_amount",
"fieldname": "tax_amount_after_discount_amount",
"fieldtype": "Currency",
"hidden": 0,
"label": "Tax Amount After Discount Amount",
"options": "Company:company:default_currency",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "item_wise_tax_detail",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Item Wise Tax Detail",
"oldfieldname": "item_wise_tax_detail",
"oldfieldtype": "Small Text",
"permlevel": 0,
"fieldname": "item_wise_tax_detail",
"fieldtype": "Small Text",
"hidden": 1,
"label": "Item Wise Tax Detail",
"oldfieldname": "item_wise_tax_detail",
"oldfieldtype": "Small Text",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "parenttype",
"fieldtype": "Data",
"hidden": 1,
"in_filter": 1,
"label": "Parenttype",
"oldfieldname": "parenttype",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"fieldname": "parenttype",
"fieldtype": "Data",
"hidden": 1,
"in_filter": 1,
"label": "Parenttype",
"oldfieldname": "parenttype",
"oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 1,
"search_index": 1
}
],
"hide_heading": 1,
"idx": 1,
"istable": 1,
"modified": "2014-05-30 03:43:39.740638",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
"owner": "Administrator",
],
"hide_heading": 1,
"idx": 1,
"istable": 1,
"modified": "2014-12-10 12:26:41.222471",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Taxes and Charges",
"owner": "Administrator",
"permissions": []
}
}

View File

@@ -46,17 +46,17 @@ cur_frm.pformat.other_charges= function(doc){
var new_val = flt(val)/flt(doc.conversion_rate);
return new_val;
}
function print_hide(fieldname) {
var doc_field = frappe.meta.get_docfield(doc.doctype, fieldname, doc.name);
return doc_field.print_hide;
}
out ='';
if (!doc.print_without_amount) {
var cl = doc.other_charges || [];
// outer table
// outer table
var out='<div><table class="noborder" style="width:100%"><tr><td style="width: 60%"></td><td>';
// main table
@@ -77,12 +77,12 @@ cur_frm.pformat.other_charges= function(doc){
// Discount Amount
if(!print_hide('discount_amount') && doc.discount_amount)
out += make_row('Discount Amount', convert_rate(doc.discount_amount), 0);
out += make_row('Discount Amount', doc.discount_amount, 0);
// grand total
if(!print_hide('grand_total_export'))
out += make_row('Grand Total', doc.grand_total_export, 1);
if(!print_hide('rounded_total_export'))
out += make_row('Rounded Total', doc.rounded_total_export, 1);
@@ -92,7 +92,7 @@ cur_frm.pformat.other_charges= function(doc){
out += '<table><tr><td style="width:25%;"><b>In Words</b></td>';
out += '<td style="width:50%;">' + doc.in_words_export + '</td></tr>';
}
out += '</table></td></tr></table></div>';
out += '</table></td></tr></table></div>';
}
return out;
}
@@ -139,14 +139,14 @@ cur_frm.fields_dict['other_charges'].grid.get_field("account_head").get_query =
"account_type": ["Tax", "Chargeable", "Income Account"],
"company": doc.company
}
}
}
}
cur_frm.fields_dict['other_charges'].grid.get_field("cost_center").get_query = function(doc) {
return{
'company': doc.company,
'group_or_ledger': "Ledger"
}
}
}
cur_frm.cscript.rate = function(doc, cdt, cdn) {

View File

@@ -97,8 +97,7 @@ def validate_account_for_auto_accounting_for_stock(gl_map):
for entry in gl_map:
if entry.account in aii_accounts:
frappe.throw(_("Account: {0} can only be updated via \
Stock Transactions").format(entry.account), StockAccountInvalidTransaction)
frappe.throw(_("Account: {0} can only be updated via Stock Transactions").format(entry.account), StockAccountInvalidTransaction)
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,

View File

@@ -45,7 +45,7 @@ pscript['onload_Accounts Browser'] = function(wrapper){
'icon-plus');
}
wrapper.appframe.set_title_right('Refresh', function() {
wrapper.appframe.set_title_right(__('Refresh'), function() {
wrapper.$company_select.change();
});

View File

@@ -1,7 +1,7 @@
frappe.pages['pos'].onload = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
title: 'Start POS',
title: __('Start POS'),
single_column: true
});

View File

@@ -163,7 +163,7 @@ def create_party_account(party, party_type, company):
company_details = frappe.db.get_value("Company", company,
["abbr", "receivables_group", "payables_group"], as_dict=True)
if not frappe.db.exists("Account", (party + " - " + company_details.abbr)):
if not frappe.db.exists("Account", (party.strip() + " - " + company_details.abbr)):
parent_account = company_details.receivables_group \
if party_type=="Customer" else company_details.payables_group
if not parent_account:

View File

@@ -3,9 +3,9 @@
"doc_type": "Journal Voucher",
"docstatus": 0,
"doctype": "Print Format",
"html": "<div style=\"position: relative\">\n\n\t{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Advice\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n{%- for label, value in (\n (_(\"Voucher Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Reference / Cheque No.\"), doc.cheque_no),\n (_(\"Reference / Cheque Date\"), frappe.utils.formatdate(doc.cheque_date))\n ) -%}\n <div class=\"row\">\n <div class=\"col-sm-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-8\">{{ value }}</div>\n </div>\n{%- endfor -%}\n\t<hr>\n\t<p>{{ _(\"This amount is in full / part settlement of the listed bills\") }}:</p>\n{%- for label, value in (\n (_(\"Amount\"), \"<strong>\" + (doc.total_amount or \"\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"References\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-sm-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-8\">{{ value }}</div>\n </div>\n {%- endfor -%}\n <hr>\n\t<div style=\"position: absolute; top: 14cm; left: 0cm;\">\n\t\tPrepared By</div>\n\t<div style=\"position: absolute; top: 14cm; left: 5.5cm;\">\n\t\tAuthorised Signatory</div>\n\t<div style=\"position: absolute; top: 14cm; left: 11cm;\">\n\t\tReceived Payment as Above</div>\n\t<div style=\"position: absolute; top: 16.4cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 6cm;\">\n\t\t<strong>A/C Payee</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.9cm; left: 12cm;\">\n\t\t{{ frappe.utils.formatdate(doc.cheque_date) }}</div>\n\t<div style=\"position: absolute; top: 17.9cm; left: 1cm;\">\n\t\t{{ doc.pay_to_recd_from }}</div>\n\t<div style=\"position: absolute; top: 18.6cm; left: 1cm; width: 7cm;\">\n\t\t{{ doc.total_amount_in_words }}</div>\n\t<div style=\"position: absolute; top: 19.7cm; left: 12cm;\">\n\t\t{{ doc.total_amount }}</div>\n</div>",
"html": "<div style=\"position: relative\">\n\n\t{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Advice\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n{%- for label, value in (\n (_(\"Voucher Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Reference / Cheque No.\"), doc.cheque_no),\n (_(\"Reference / Cheque Date\"), frappe.utils.formatdate(doc.cheque_date))\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n{%- endfor -%}\n\t<hr>\n\t<p>{{ _(\"This amount is in full / part settlement of the listed bills\") }}:</p>\n{%- for label, value in (\n (_(\"Amount\"), \"<strong>\" + (doc.total_amount or \"\") + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"References\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-8\">{{ value }}</div>\n </div>\n {%- endfor -%}\n <hr>\n\t<div style=\"position: absolute; top: 14cm; left: 0cm;\">\n\t\tPrepared By</div>\n\t<div style=\"position: absolute; top: 14cm; left: 5.5cm;\">\n\t\tAuthorised Signatory</div>\n\t<div style=\"position: absolute; top: 14cm; left: 11cm;\">\n\t\tReceived Payment as Above</div>\n\t<div style=\"position: absolute; top: 16.4cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 6cm;\">\n\t\t<strong>A/C Payee</strong></div>\n\t<div style=\"position: absolute; top: 16.7cm; left: 5.9cm;\">\n\t\t<strong>_____________</strong></div>\n\t<div style=\"position: absolute; top: 16.9cm; left: 12cm;\">\n\t\t{{ frappe.utils.formatdate(doc.cheque_date) }}</div>\n\t<div style=\"position: absolute; top: 17.9cm; left: 1cm;\">\n\t\t{{ doc.pay_to_recd_from }}</div>\n\t<div style=\"position: absolute; top: 18.6cm; left: 1cm; width: 7cm;\">\n\t\t{{ doc.total_amount_in_words }}</div>\n\t<div style=\"position: absolute; top: 19.7cm; left: 12cm;\">\n\t\t{{ doc.total_amount }}</div>\n</div>",
"idx": 1,
"modified": "2014-09-09 03:27:13.708596",
"modified": "2015-01-12 11:03:17.032512",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cheque Printing Format",

View File

@@ -4,9 +4,9 @@
"doc_type": "Journal Voucher",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + doc.total_amount + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Credit Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Credit To\"), doc.pay_to_recd_from),\n (_(\"Date\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Amount\"), \"<strong>\" + frappe.utils.cstr(doc.total_amount) + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n\n",
"idx": 2,
"modified": "2014-08-29 13:20:15.789533",
"modified": "2015-01-12 11:02:25.716825",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Credit Note",

View File

@@ -1,15 +1,15 @@
{
"creation": "2012-05-01 12:46:31",
"doc_type": "Journal Voucher",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Received From\"), doc.pay_to_recd_from),\n (_(\"Amount\"), \"<strong>\" + doc.total_amount + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-sm-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-sm-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n",
"idx": 1,
"modified": "2014-08-29 15:55:34.248384",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Receipt Voucher",
"owner": "Administrator",
"print_format_type": "Server",
"creation": "2012-05-01 12:46:31",
"doc_type": "Journal Voucher",
"docstatus": 0,
"doctype": "Print Format",
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header -%}\n<div class=\"page-break\">\n {%- if not doc.get(\"print_heading\") and not doc.get(\"select_print_heading\") \n and doc.set(\"select_print_heading\", _(\"Payment Receipt Note\")) -%}{%- endif -%}\n {{ add_header(0, 1, doc, letter_head, no_letterhead) }}\n\n {%- for label, value in (\n (_(\"Received On\"), frappe.utils.formatdate(doc.voucher_date)),\n (_(\"Received From\"), doc.pay_to_recd_from),\n (_(\"Amount\"), \"<strong>\" + frappe.utils.cstr(doc.total_amount or 0) + \"</strong><br>\" + (doc.total_amount_in_words or \"\") + \"<br>\"),\n (_(\"Remarks\"), doc.remark)\n ) -%}\n <div class=\"row\">\n <div class=\"col-xs-3\"><label class=\"text-right\">{{ label }}</label></div>\n <div class=\"col-xs-9\">{{ value }}</div>\n </div>\n\n {%- endfor -%}\n\n <hr>\n <br>\n <p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n </p>\n</div>\n\n",
"idx": 1,
"modified": "2015-01-16 11:03:22.893209",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Receipt Voucher",
"owner": "Administrator",
"print_format_type": "Server",
"standard": "Yes"
}
}

View File

@@ -3,9 +3,9 @@
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"60%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"10%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Rate\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.entries -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}</td>\n\t\t\t<td class=\"text-right\">{{ item.amount }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total_export\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.other_charges -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total_export\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n{% if doc.get(\"other_charges\", filters={\"included_in_print_rate\": 1}) %}\n<hr>\n<p><b>Taxes Included:</b></p>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t{%- for row in doc.other_charges -%}\n\t\t{%- if row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t<tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n{%- endif -%}\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"60%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"10%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Rate\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.entries -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}</td>\n\t\t\t<td class=\"text-right\">{{ item.amount }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total_export\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.other_charges -%}\n\t\t{%- if not row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total_export\") }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n{% if doc.get(\"other_charges\", filters={\"included_in_print_rate\": 1}) %}\n<hr>\n<p><b>Taxes Included:</b></p>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t{%- for row in doc.other_charges -%}\n\t\t{%- if row.included_in_print_rate -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ row.get_formatted(\"tax_amount_after_discount_amount\", doc) }}\n\t\t\t</td>\n\t\t<tr>\n\t\t{%- endif -%}\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n{%- endif -%}\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
"idx": 1,
"modified": "2014-07-22 02:08:26.603223",
"modified": "2014-12-10 12:37:10.854370",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",

View File

@@ -30,7 +30,8 @@ def execute(filters=None):
data = []
for gle in entries:
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \
or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date \
or (gle.against_voucher_type == "Purchase Order"):
voucher_details = voucher_detail_map.get(gle.voucher_type, {}).get(gle.voucher_no, {})
invoiced_amount = gle.credit > 0 and gle.credit or 0
@@ -67,12 +68,12 @@ def execute(filters=None):
def get_columns(supplier_naming_by):
columns = [
"Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110",
"Voucher No::120", "::30", "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80",
"Invoiced Amount:Currency:100", "Paid Amount:Currency:100",
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
"Supplier:Link/Supplier:150"
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150", _("Voucher Type") + "::110",
_("Voucher No") + "::120", "::30", _("Due Date") + ":Date:80", _("Bill No") + "::80", _("Bill Date") + ":Date:80",
_("Invoiced Amount") + ":Currency:100", _("Paid Amount") + ":Currency:100",
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100",
_("Supplier") + ":Link/Supplier:150"
]
if supplier_naming_by == "Naming Series":

View File

@@ -13,20 +13,20 @@ class AccountsReceivableReport(object):
self.age_as_on = getdate(nowdate()) \
if self.filters.report_date > getdate(nowdate()) \
else self.filters.report_date
def run(self):
customer_naming_by = frappe.db.get_value("Selling Settings", None, "cust_master_name")
return self.get_columns(customer_naming_by), self.get_data(customer_naming_by)
def get_columns(self, customer_naming_by):
columns = [
"Posting Date:Date:80", "Account:Link/Account:150",
"Voucher Type::110", "Voucher No::120", "::30",
"Due Date:Date:80",
"Invoiced Amount:Currency:100", "Payment Received:Currency:100",
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
"Customer:Link/Customer:200"
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150",
_("Voucher Type") + "::110", _("Voucher No") + ":Dynamic Link/Voucher Type:120",
_("Due Date") + ":Date:80",
_("Invoiced Amount") + ":Currency:100", _("Payment Received") + ":Currency:100",
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100",
_("Customer") + ":Link/Customer:200"
]
if customer_naming_by == "Naming Series":
@@ -63,35 +63,33 @@ class AccountsReceivableReport(object):
row += [self.get_territory(gle.account), gle.remarks]
data.append(row)
for i in range(0, len(data)):
data[i].insert(4, """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
% ("/".join(["#Form", data[i][2], data[i][3]]),))
return data
def get_entries_after(self, report_date):
# returns a distinct list
return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries()
if getdate(e.posting_date) > report_date]))
def get_entries_till(self, report_date):
# returns a generator
return (e for e in self.get_gl_entries()
return (e for e in self.get_gl_entries()
if getdate(e.posting_date) <= report_date)
def is_receivable(self, gle, future_vouchers):
return (
# advance
(not gle.against_voucher) or
(not gle.against_voucher) or
# against sales order
(gle.against_voucher_type == "Sales Order") or
# sales invoice
(gle.against_voucher==gle.voucher_no and gle.debit > 0) or
(gle.against_voucher==gle.voucher_no and gle.debit > 0) or
# entries adjusted with future vouchers
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
)
def get_outstanding_amount(self, gle, report_date):
payment_received = 0.0
for e in self.get_gl_entries_for(gle.account, gle.voucher_type, gle.voucher_no):
@@ -99,7 +97,7 @@ class AccountsReceivableReport(object):
payment_received += (flt(e.credit) - flt(e.debit))
return flt(gle.debit) - flt(gle.credit) - payment_received
def get_customer(self, account):
return self.get_account_map().get(account, {}).get("customer") or ""
@@ -108,25 +106,25 @@ class AccountsReceivableReport(object):
def get_territory(self, account):
return self.get_account_map().get(account, {}).get("territory") or ""
def get_account_map(self):
if not hasattr(self, "account_map"):
self.account_map = dict(((r.name, r) for r in frappe.db.sql("""select
self.account_map = dict(((r.name, r) for r in frappe.db.sql("""select
acc.name, cust.name as customer, cust.customer_name, cust.territory
from `tabAccount` acc left join `tabCustomer` cust
from `tabAccount` acc left join `tabCustomer` cust
on cust.name=acc.master_name where acc.master_type="Customer" """, as_dict=True)))
return self.account_map
def get_due_date(self, gle):
if not hasattr(self, "invoice_due_date_map"):
# TODO can be restricted to posting date
self.invoice_due_date_map = dict(frappe.db.sql("""select name, due_date
from `tabSales Invoice` where docstatus=1"""))
return gle.voucher_type == "Sales Invoice" \
and self.invoice_due_date_map.get(gle.voucher_no) or ""
def get_gl_entries(self):
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions()
@@ -134,15 +132,15 @@ class AccountsReceivableReport(object):
where docstatus < 2 {0} order by posting_date, account""".format(conditions),
values, as_dict=True)
return self.gl_entries
def prepare_conditions(self):
conditions = [""]
values = {}
if self.filters.company:
conditions.append("company=%(company)s")
values["company"] = self.filters.company
if self.filters.account:
conditions.append("account=%(account)s")
values["account"] = self.filters.account
@@ -151,11 +149,11 @@ class AccountsReceivableReport(object):
if not account_map:
frappe.throw(_("No Customer Accounts found."))
else:
accounts_list = ['"{0}"'.format(ac) for ac in account_map]
accounts_list = ["'{0}'".format(frappe.db.escape(ac)) for ac in account_map]
conditions.append("account in ({0})".format(", ".join(accounts_list)))
return " and ".join(conditions), values
def get_gl_entries_for(self, account, against_voucher_type, against_voucher):
if not hasattr(self, "gl_entries_map"):
self.gl_entries_map = {}
@@ -165,7 +163,7 @@ class AccountsReceivableReport(object):
.setdefault(gle.against_voucher_type, {})\
.setdefault(gle.against_voucher, [])\
.append(gle)
return self.gl_entries_map.get(account, {})\
.get(against_voucher_type, {})\
.get(against_voucher, [])
@@ -178,15 +176,15 @@ def get_ageing_data(age_as_on, entry_date, outstanding_amount):
outstanding_range = [0.0, 0.0, 0.0, 0.0]
if not (age_as_on and entry_date):
return [0] + outstanding_range
age = (getdate(age_as_on) - getdate(entry_date)).days or 0
index = None
for i, days in enumerate([30, 60, 90]):
if age <= days:
index = i
break
if index is None: index = 3
outstanding_range[index] = outstanding_amount
return [age] + outstanding_range

View File

@@ -14,9 +14,9 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Clearance Date:Date:110", "Against Account:Link/Account:200",
"Debit:Currency:120", "Credit:Currency:120"
return [_("Journal Voucher") + ":Link/Journal Voucher:140", _("Account") + ":Link/Account:140",
_("Posting Date") + ":Date:100", _("Clearance Date") + ":Date:110", _("Against Account") + ":Link/Account:200",
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120"
]
def get_conditions(filters):

View File

@@ -16,31 +16,31 @@
</thead>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
{% if (data[i].posting_date) { %}
{% if (data[i][__("Posting Date")]) { %}
<tr>
<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
<td>{%= data[i].journal_voucher %}</td>
<td>{%= __("Against") %}: {%= data[i].against_account %}
{% if (data[i].reference) { %}
<br>{%= __("Reference") %}: {%= data[i].reference %}
{% if (data[i].ref_date) { %}
<br>{%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i].ref_date) %}
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Journal Voucher")] %}</td>
<td>{%= __("Against") %}: {%= data[i][__("Against Account")] %}
{% if (data[i][__("Reference")]) { %}
<br>{%= __("Reference") %}: {%= data[i][__("Reference")] %}
{% if (data[i][__("Ref Date")]) { %}
<br>{%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i][__("Ref Date")]) %}
{% } %}
{% } %}
{% if (data[i].clearance_date) { %}
<br>{%= __("Clearance Date") %}: {%= dateutil.str_to_user(data[i].clearance_date) %}
{% if (data[i][__("Clearance Date")]) { %}
<br>{%= __("Clearance Date") %}: {%= dateutil.str_to_user(data[i][__("Clearance Date")]) %}
{% } %}
</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
</tr>
{% } else { %}
<tr>
<td></td>
<td></td>
<td>{%= data[i].journal_voucher %}</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
<td>{%= data[i][__("Journal Voucher")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
</tr>
{% } %}
{% } %}

View File

@@ -26,7 +26,7 @@ def execute(filters=None):
amounts_not_reflected_in_system = frappe.db.sql("""select sum(ifnull(jvd.debit, 0) - ifnull(jvd.credit, 0))
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%s
and jv.posting_date > %s and jv.clearance_date <= %s
and jv.posting_date > %s and jv.clearance_date <= %s and ifnull(jv.is_opening, 'No') = 'No'
""", (filters["account"], filters["report_date"], filters["report_date"]))
amounts_not_reflected_in_system = flt(amounts_not_reflected_in_system[0][0]) \
@@ -47,9 +47,9 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Posting Date:Date:100", "Journal Voucher:Link/Journal Voucher:220",
"Debit:Currency:120", "Credit:Currency:120",
"Against Account:Link/Account:200", "Reference::100", "Ref Date:Date:110", "Clearance Date:Date:110"
return [_("Posting Date") + ":Date:100", _("Journal Voucher") + ":Link/Journal Voucher:220",
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Against Account") + ":Link/Account:200", _("Reference") + "::100", _("Ref Date") + ":Date:110", _("Clearance Date") + ":Date:110"
]
def get_entries(filters):
@@ -61,6 +61,7 @@ def get_entries(filters):
where jvd.parent = jv.name and jv.docstatus=1
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'
order by jv.name DESC""", filters, as_list=1)
return entries

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe.utils import flt
from frappe.utils import formatdate
import time
from erpnext.accounts.utils import get_fiscal_year
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
@@ -44,21 +45,21 @@ def get_columns(filters):
msgprint(_("Please specify") + ": " + label,
raise_exception=True)
columns = ["Cost Center:Link/Cost Center:120", "Account:Link/Account:120"]
columns = [_("Cost Center") + ":Link/Cost Center:120", _("Account") + ":Link/Account:120"]
group_months = False if filters["period"] == "Monthly" else True
for from_date, to_date in get_period_date_ranges(filters["period"], filters["fiscal_year"]):
for label in ["Target (%s)", "Actual (%s)", "Variance (%s)"]:
for label in [_("Target") + " (%s)", _("Actual") + " (%s)", _("Variance") + " (%s)"]:
if group_months:
label = label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))
label = label % (formatdate(from_date, format_string="MMM") + " - " + formatdate(from_date, format_string="MMM"))
else:
label = label % from_date.strftime("%b")
label = label % formatdate(from_date, format_string="MMM")
columns.append(label+":Float:120")
return columns + ["Total Target:Float:120", "Total Actual:Float:120",
"Total Variance:Float:120"]
return columns + [_("Total Target") + ":Float:120", _("Total Actual") + ":Float:120",
_("Total Variance") + ":Float:120"]
#Get cost center & target details
def get_costcenter_target_details(filters):

View File

@@ -22,23 +22,23 @@
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
<tr>
{% if(data[i].posting_date) { %}
<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
<td>{%= data[i].voucher_type%}
<br>{%= data[i].voucher_no %}</td>
<td>{%= data[i].account %}
<br>{%= __("Against") %}: {%= data[i].against_account %}
<br>{%= __("Remarks") %}: {%= data[i].remarks %}</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
{% if(data[i][__("Posting Date")]) { %}
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Voucher Type")] %}
<br>{%= data[i][__("Voucher No")] %}</td>
<td>{%= data[i][__("Account")] %}
<br>{%= __("Against") %}: {%= data[i][__("Against Account")] %}
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
{% } else { %}
<td></td>
<td></td>
<td><b>{%= data[i].account || "&nbsp;" %}</b></td>
<td><b>{%= data[i][__("Account")] || "&nbsp;" %}</b></td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].debit) %}</td>
{%= data[i][__("Account")] && format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].credit) %}</td>
{%= data[i][__("Account")] && format_currency(data[i][__("Credit")]) %}</td>
{% } %}
</tr>
{% } %}

View File

@@ -34,9 +34,9 @@ def validate_filters(filters, account_details):
frappe.throw(_("From Date must be before To Date"))
def get_columns():
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Float:100",
"Credit:Float:100", "Voucher Type::120", "Voucher No::160", "Link::20",
"Against Account::120", "Cost Center:Link/Cost Center:100", "Remarks::400"]
return [_("Posting Date") + ":Date:100", _("Account") + ":Link/Account:200", _("Debit") + ":Float:100",
_("Credit") + ":Float:100", _("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160",
_("Against Account") + "::120", _("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400"]
def get_result(filters, account_details):
gl_entries = get_gl_entries(filters)
@@ -162,15 +162,6 @@ def get_result_as_list(data):
for d in data:
result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
get_voucher_link(d.get("voucher_type"), d.get("voucher_no")),
d.get("against"), d.get("cost_center"), d.get("remarks")])
return result
def get_voucher_link(voucher_type, voucher_no):
icon = ""
if voucher_type and voucher_no:
icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;">
</i></a>""" % ("/".join(["#Form", voucher_type, voucher_no]))
return icon

View File

@@ -3,34 +3,35 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from erpnext.stock.utils import get_buying_amount, get_sales_bom_buying_amount
def execute(filters=None):
if not filters: filters = {}
stock_ledger_entries = get_stock_ledger_entries(filters)
source = get_source_data(filters)
item_sales_bom = get_item_sales_bom()
columns = ["Delivery Note/Sales Invoice::120", "Link::30", "Posting Date:Date", "Posting Time",
"Item Code:Link/Item", "Item Name", "Description", "Warehouse:Link/Warehouse",
"Qty:Float", "Selling Rate:Currency", "Avg. Buying Rate:Currency",
"Selling Amount:Currency", "Buying Amount:Currency",
"Gross Profit:Currency", "Gross Profit %:Percent", "Project:Link/Project"]
columns = [_("Delivery Note/Sales Invoice") + "::120", _("Link") + "::30", _("Posting Date") + ":Date", _("Posting Time"),
_("Item Code") + ":Link/Item", _("Item Name"), _("Description"), _("Warehouse") + ":Link/Warehouse",
_("Qty") + ":Float", _("Selling Rate") + ":Currency", _("Avg. Buying Rate") + ":Currency",
_("Selling Amount") + ":Currency", _("Buying Amount") + ":Currency",
_("Gross Profit") + ":Currency", _("Gross Profit %") + ":Percent", _("Project") + ":Link/Project"]
data = []
for row in source:
selling_amount = flt(row.base_amount)
item_sales_bom_map = item_sales_bom.get(row.parenttype, {}).get(row.name, frappe._dict())
if item_sales_bom_map.get(row.item_code):
buying_amount = get_sales_bom_buying_amount(row.item_code, row.warehouse,
buying_amount = get_sales_bom_buying_amount(row.item_code, row.warehouse,
row.parenttype, row.name, row.item_row, stock_ledger_entries, item_sales_bom_map)
else:
buying_amount = get_buying_amount(row.parenttype, row.name, row.item_row,
stock_ledger_entries.get((row.item_code, row.warehouse), []))
buying_amount = buying_amount > 0 and buying_amount or 0
gross_profit = selling_amount - buying_amount
@@ -38,41 +39,41 @@ def execute(filters=None):
gross_profit_percent = (gross_profit / selling_amount) * 100.0
else:
gross_profit_percent = 0.0
icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
% ("/".join(["#Form", row.parenttype, row.name]),)
data.append([row.name, icon, row.posting_date, row.posting_time, row.item_code, row.item_name,
row.description, row.warehouse, row.qty, row.base_rate,
row.description, row.warehouse, row.qty, row.base_rate,
row.qty and (buying_amount / row.qty) or 0, row.base_amount, buying_amount,
gross_profit, gross_profit_percent, row.project])
return columns, data
def get_stock_ledger_entries(filters):
def get_stock_ledger_entries(filters):
query = """select item_code, voucher_type, voucher_no,
voucher_detail_no, posting_date, posting_time, stock_value,
warehouse, actual_qty as qty
from `tabStock Ledger Entry`"""
if filters.get("company"):
query += """ where company=%(company)s"""
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"
res = frappe.db.sql(query, filters, as_dict=True)
out = {}
for r in res:
if (r.item_code, r.warehouse) not in out:
out[(r.item_code, r.warehouse)] = []
out[(r.item_code, r.warehouse)].append(r)
return out
def get_item_sales_bom():
item_sales_bom = {}
for d in frappe.db.sql("""select parenttype, parent, parent_item,
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
from `tabPacked Item` where docstatus=1""", as_dict=True):
@@ -80,7 +81,7 @@ def get_item_sales_bom():
frappe._dict()).setdefault(d.parent_item, []).append(d)
return item_sales_bom
def get_source_data(filters):
conditions = ""
if filters.get("company"):
@@ -89,9 +90,9 @@ def get_source_data(filters):
conditions += " and posting_date>=%(from_date)s"
if filters.get("to_date"):
conditions += " and posting_date<=%(to_date)s"
delivery_note_items = frappe.db.sql("""select item.parenttype, dn.name,
dn.posting_date, dn.posting_time, dn.project_name,
delivery_note_items = frappe.db.sql("""select item.parenttype, dn.name,
dn.posting_date, dn.posting_time, dn.project_name,
item.item_code, item.item_name, item.description, item.warehouse,
item.qty, item.base_rate, item.base_amount, item.name as "item_row",
timestamp(dn.posting_date, dn.posting_time) as posting_datetime
@@ -99,7 +100,7 @@ def get_source_data(filters):
where item.parent = dn.name and dn.docstatus = 1 %s
order by dn.posting_date desc, dn.posting_time desc""" % (conditions,), filters, as_dict=1)
sales_invoice_items = frappe.db.sql("""select item.parenttype, si.name,
sales_invoice_items = frappe.db.sql("""select item.parenttype, si.name,
si.posting_date, si.posting_time, si.project_name,
item.item_code, item.item_name, item.description, item.warehouse,
item.qty, item.base_rate, item.base_amount, item.name as "item_row",
@@ -108,9 +109,9 @@ def get_source_data(filters):
where item.parent = si.name and si.docstatus = 1 %s
and si.update_stock = 1
order by si.posting_date desc, si.posting_time desc""" % (conditions,), filters, as_dict=1)
source = delivery_note_items + sales_invoice_items
if len(source) > len(delivery_note_items):
source.sort(key=lambda d: d.posting_datetime, reverse=True)
return source
return source

View File

@@ -3,46 +3,47 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
last_col = len(columns)
item_list = get_items(filters)
aii_account_map = get_aii_accounts()
if item_list:
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
data = []
for d in item_list:
expense_account = d.expense_account or aii_account_map.get(d.company)
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date,
d.supplier_name, d.credit_to, d.project_name, d.company, d.purchase_order,
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date,
d.supplier_name, d.credit_to, d.project_name, d.company, d.purchase_order,
d.purchase_receipt, expense_account, d.qty, d.base_rate, d.base_amount]
for tax in tax_accounts:
row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0))
total_tax = sum(row[last_col:])
row += [total_tax, d.base_amount + total_tax]
data.append(row)
return columns, data
def get_columns():
return ["Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Customer:120",
"Supplier Account:Link/Account:120", "Project:Link/Project:80", "Company:Link/Company:100",
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100",
"Expense Account:Link/Account:140", "Qty:Float:120", "Rate:Currency:120",
"Amount:Currency:120"]
return [_("Item Code") + ":Link/Item:120", _("Item Name") + "::120", _("Item Group") + ":Link/Item Group:100",
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80", _("Supplier") + ":Link/Customer:120",
_("Supplier Account") + ":Link/Account:120", _("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
_("Purchase Order") + ":Link/Purchase Order:100", _("Purchase Receipt") + ":Link/Purchase Receipt:100",
_("Expense Account") + ":Link/Account:140", _("Qty") + ":Float:120", _("Rate") + ":Currency:120",
_("Amount") + ":Currency:120"]
def get_conditions(filters):
conditions = ""
for opts in (("company", " and company=%(company)s"),
("account", " and pi.credit_to = %(account)s"),
("item_code", " and pi_item.item_code = %(item_code)s"),
@@ -52,48 +53,56 @@ def get_conditions(filters):
conditions += opts[1]
return conditions
def get_items(filters):
conditions = get_conditions(filters)
match_conditions = frappe.build_match_conditions("Purchase Invoice")
return frappe.db.sql("""select pi_item.parent, pi.posting_date, pi.credit_to, pi.company,
pi.supplier, pi.remarks, pi_item.item_code, pi_item.item_name, pi_item.item_group,
pi_item.project_name, pi_item.purchase_order, pi_item.purchase_receipt,
return frappe.db.sql("""select pi_item.parent, pi.posting_date, pi.credit_to, pi.company,
pi.supplier, pi.remarks, pi.net_total, pi_item.item_code, pi_item.item_name, pi_item.item_group,
pi_item.project_name, pi_item.purchase_order, pi_item.purchase_receipt,
pi_item.expense_account, pi_item.qty, pi_item.base_rate, pi_item.base_amount, pi.supplier_name
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
where pi.name = pi_item.parent and pi.docstatus = 1 %s %s
order by pi.posting_date desc, pi_item.item_code desc""" % (conditions, match_conditions), filters, as_dict=1)
def get_aii_accounts():
return dict(frappe.db.sql("select name, stock_received_but_not_billed from tabCompany"))
def get_tax_accounts(item_list, columns):
import json
item_tax = {}
tax_accounts = []
tax_details = frappe.db.sql("""select parent, account_head, item_wise_tax_detail
from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice'
and docstatus = 1 and ifnull(account_head, '') != '' and category in ('Total', 'Valuation and Total')
and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list]))
for parent, account_head, item_wise_tax_detail in tax_details:
invoice_wise_items = {}
for d in item_list:
invoice_wise_items.setdefault(d.parent, []).append(d)
tax_details = frappe.db.sql("""select parent, account_head, item_wise_tax_detail, charge_type, tax_amount
from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice'
and docstatus = 1 and ifnull(account_head, '') != '' and category in ('Total', 'Valuation and Total')
and parent in (%s)""" % ', '.join(['%s']*len(invoice_wise_items)), tuple(invoice_wise_items.keys()))
for parent, account_head, item_wise_tax_detail, charge_type, tax_amount in tax_details:
if account_head not in tax_accounts:
tax_accounts.append(account_head)
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
for item, tax_amount in item_wise_tax_detail.items():
item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \
flt(tax_amount[1]) if isinstance(tax_amount, list) else flt(tax_amount)
except ValueError:
continue
elif charge_type == "Actual" and tax_amount:
for d in invoice_wise_items.get(parent, []):
item_tax.setdefault(parent, {}).setdefault(d.item_code, {})[account_head] = \
(tax_amount * d.base_amount) / d.net_total
tax_accounts.sort()
columns += [account_head + ":Currency:80" for account_head in tax_accounts]
columns += ["Total Tax:Currency:80", "Total:Currency:80"]
return item_tax, tax_accounts
return item_tax, tax_accounts

View File

@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe.utils import flt
def execute(filters=None):
@@ -13,36 +14,36 @@ def execute(filters=None):
item_list = get_items(filters)
if item_list:
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
data = []
for d in item_list:
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date,
d.customer_name, d.debit_to, d.territory, d.project_name, d.company, d.sales_order,
row = [d.item_code, d.item_name, d.item_group, d.parent, d.posting_date,
d.customer_name, d.debit_to, d.territory, d.project_name, d.company, d.sales_order,
d.delivery_note, d.income_account, d.qty, d.base_rate, d.base_amount]
for tax in tax_accounts:
row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0))
total_tax = sum(row[last_col:])
row += [total_tax, d.base_amount + total_tax]
data.append(row)
return columns, data
def get_columns():
return [
"Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
"Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer:Link/Customer:120",
"Customer Account:Link/Account:120", "Territory:Link/Territory:80",
"Project:Link/Project:80", "Company:Link/Company:100", "Sales Order:Link/Sales Order:100",
"Delivery Note:Link/Delivery Note:100", "Income Account:Link/Account:140",
"Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120"
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120", _("Item Group") + ":Link/Item Group:100",
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
_("Customer Account") + ":Link/Account:120", _("Territory") + ":Link/Territory:80",
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100", _("Sales Order") + ":Link/Sales Order:100",
_("Delivery Note") + ":Link/Delivery Note:100", _("Income Account") + ":Link/Account:140",
_("Qty") + ":Float:120", _("Rate") + ":Currency:120", _("Amount") + ":Currency:120"
]
def get_conditions(filters):
conditions = ""
for opts in (("company", " and company=%(company)s"),
("account", " and si.debit_to = %(account)s"),
("item_code", " and si_item.item_code = %(item_code)s"),
@@ -52,32 +53,36 @@ def get_conditions(filters):
conditions += opts[1]
return conditions
def get_items(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""select si_item.parent, si.posting_date, si.debit_to, si.project_name,
si.customer, si.remarks, si.territory, si.company, si_item.item_code, si_item.item_name,
si_item.item_group, si_item.sales_order, si_item.delivery_note, si_item.income_account,
return frappe.db.sql("""select si_item.parent, si.posting_date, si.debit_to, si.project_name,
si.customer, si.remarks, si.territory, si.company, si.net_total, si_item.item_code, si_item.item_name,
si_item.item_group, si_item.sales_order, si_item.delivery_note, si_item.income_account,
si_item.qty, si_item.base_rate, si_item.base_amount, si.customer_name
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 %s
from `tabSales Invoice` si, `tabSales Invoice Item` si_item
where si.name = si_item.parent and si.docstatus = 1 %s
order by si.posting_date desc, si_item.item_code desc""" % conditions, filters, as_dict=1)
def get_tax_accounts(item_list, columns):
import json
item_tax = {}
tax_accounts = []
tax_details = frappe.db.sql("""select parent, account_head, item_wise_tax_detail
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
invoice_wise_items = {}
for d in item_list:
invoice_wise_items.setdefault(d.parent, []).append(d)
tax_details = frappe.db.sql("""select parent, account_head, item_wise_tax_detail, charge_type, tax_amount
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
and docstatus = 1 and ifnull(account_head, '') != ''
and parent in (%s)""" % ', '.join(['%s']*len(item_list)),
tuple([item.parent for item in item_list]))
for parent, account_head, item_wise_tax_detail in tax_details:
and parent in (%s)""" % ', '.join(['%s']*len(invoice_wise_items)),
tuple(invoice_wise_items.keys()))
for parent, account_head, item_wise_tax_detail, charge_type, tax_amount in tax_details:
if account_head not in tax_accounts:
tax_accounts.append(account_head)
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
@@ -86,9 +91,13 @@ def get_tax_accounts(item_list, columns):
flt(tax_amount[1]) if isinstance(tax_amount, list) else flt(tax_amount)
except ValueError:
continue
elif charge_type == "Actual" and tax_amount:
for d in invoice_wise_items.get(parent, []):
item_tax.setdefault(parent, {}).setdefault(d.item_code, {})[account_head] = \
flt((tax_amount * d.base_amount) / d.net_total)
tax_accounts.sort()
columns += [account_head + ":Currency:80" for account_head in tax_accounts]
columns += ["Total Tax:Currency:80", "Total:Currency:80"]
return item_tax, tax_accounts
return item_tax, tax_accounts

View File

@@ -37,11 +37,11 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130",
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
return [_("Journal Voucher") + ":Link/Journal Voucher:140", _("Account") + ":Link/Account:140",
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100"
]
def get_conditions(filters):

View File

@@ -63,11 +63,11 @@ def execute(filters=None):
def get_columns(invoice_list):
"""return columns based on filters"""
columns = [
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier Id::120",
"Supplier Name::120", "Supplier Account:Link/Account:120",
"Account Group:LInk/Account:120", "Project:Link/Project:80", "Bill No::120",
"Bill Date:Date:80", "Remarks::150",
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100"
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80", _("Supplier Id") + "::120",
_("Supplier Name") + "::120", _("Supplier Account") + ":Link/Account:120",
_("Account Group") + ":Link/Account:120", _("Project") + ":Link/Project:80", _("Bill No") + "::120",
_("Bill Date") + ":Date:80", _("Remarks") + "::150",
_("Purchase Order") + ":Link/Purchase Order:100", _("Purchase Receipt") + ":Link/Purchase Receipt:100"
]
expense_accounts = tax_accounts = expense_columns = tax_columns = []

View File

@@ -11,4 +11,4 @@ def execute(filters=None):
conditions = get_columns(filters, "Sales Invoice")
data = get_data(filters, conditions)
return conditions["columns"], data
return conditions["columns"], data

View File

@@ -63,10 +63,10 @@ def execute(filters=None):
def get_columns(invoice_list):
"""return columns based on filters"""
columns = [
"Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer Id::120",
"Customer Name::120", "Customer Account:Link/Account:120", "Account Group:LInk/Account:120",
"Territory:Link/Territory:80", "Project:Link/Project:80", "Remarks::150",
"Sales Order:Link/Sales Order:100", "Delivery Note:Link/Delivery Note:100"
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80", _("Customer Id") + "::120",
_("Customer Name") + "::120", _("Customer Account") + ":Link/Account:120", _("Account Group") + ":Link/Account:120",
_("Territory") + ":Link/Territory:80", _("Project") + ":Link/Project:80", _("Remarks") + "::150",
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100"
]
income_accounts = tax_accounts = income_columns = tax_columns = []

View File

@@ -28,7 +28,7 @@ def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
from `tabFiscal Year` where %s order by year_start_date desc""" % cond)
if not fy:
error_msg = _("""{0} {1} not in any Fiscal Year""").format(label, formatdate(date))
error_msg = _("""{0} {1} not in any Fiscal Year. For more details check {2}.""").format(label, formatdate(date), "https://erpnext.com/kb/accounts/fiscal-year-error")
if verbose: frappe.msgprint(error_msg)
raise FiscalYearError, error_msg
@@ -391,3 +391,42 @@ def get_stock_rbnb_difference(posting_date, company):
# Amount should be credited
return flt(stock_rbnb) + flt(sys_bal)
def get_outstanding_invoices(amount_query, account):
all_outstanding_vouchers = []
outstanding_voucher_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date,
ifnull(sum({amount_query}), 0) as invoice_amount
from
`tabGL Entry`
where
account = %s and {amount_query} > 0
group by voucher_type, voucher_no
""".format(amount_query = amount_query), account, as_dict = True)
for d in outstanding_voucher_list:
payment_amount = frappe.db.sql("""
select ifnull(sum(ifnull({amount_query}, 0)), 0)
from
`tabGL Entry`
where
account = %s and {amount_query} < 0
and against_voucher_type = %s and ifnull(against_voucher, '') = %s
""".format(**{
"amount_query": amount_query
}), (account, d.voucher_type, d.voucher_no))
payment_amount = -1*payment_amount[0][0] if payment_amount else 0
if d.invoice_amount > payment_amount:
all_outstanding_vouchers.append({
'voucher_no': d.voucher_no,
'voucher_type': d.voucher_type,
'posting_date': d.posting_date,
'invoice_amount': flt(d.invoice_amount),
'outstanding_amount': d.invoice_amount - payment_amount
})
return all_outstanding_vouchers

View File

@@ -71,7 +71,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
},
contact_person: function() {
this.supplier_address();
erpnext.utils.get_contact_details(this.frm);
},
buying_price_list: function() {
@@ -209,24 +209,17 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
calculate_totals: function() {
var tax_count = this.frm.tax_doclist.length;
this.frm.doc.grand_total = flt(tax_count ?
this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total,
precision("grand_total"));
this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total /
this.frm.doc.conversion_rate, precision("grand_total_import"));
this.frm.doc.grand_total = flt(tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total);
this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
precision("total_tax"));
this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("total_tax"));
this.frm.doc.grand_total = flt(this.frm.doc.grand_total, precision("grand_total"));
// rounded totals
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
}
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total_import", this.frm.doc.name)) {
this.frm.doc.rounded_total_import = Math.round(this.frm.doc.grand_total_import);
}
// other charges added/deducted
this.frm.doc.other_charges_added = 0.0
this.frm.doc.other_charges_deducted = 0.0
@@ -244,6 +237,16 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
frappe.model.round_floats_in(this.frm.doc,
["other_charges_added", "other_charges_deducted"]);
}
this.frm.doc.grand_total_import = flt((this.frm.doc.other_charges_added || this.frm.doc.other_charges_deducted) ?
flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate) : this.frm.doc.net_total_import);
this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total_import, precision("grand_total_import"));
if(frappe.meta.get_docfield(this.frm.doc.doctype, "rounded_total_import", this.frm.doc.name)) {
this.frm.doc.rounded_total_import = Math.round(this.frm.doc.grand_total_import);
}
this.frm.doc.other_charges_added_import = flt(this.frm.doc.other_charges_added /
this.frm.doc.conversion_rate, precision("other_charges_added_import"));
this.frm.doc.other_charges_deducted_import = flt(this.frm.doc.other_charges_deducted /

View File

@@ -3,15 +3,13 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt
from frappe.utils import flt
from frappe import _
from erpnext.stock.doctype.item.item import get_last_purchase_details
from erpnext.controllers.buying_controller import BuyingController
class PurchaseCommon(BuyingController):
def update_last_purchase_rate(self, obj, is_submit):
"""updates last_purchase_rate in item table for each item"""
@@ -123,27 +121,6 @@ class PurchaseCommon(BuyingController):
else:
chk_dupl_itm.append(f)
def get_qty(self, curr_doctype, ref_tab_fname, ref_tab_dn, ref_doc_tname, transaction, curr_parent_name):
# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
#------------------------------
# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
# i.e. in PO uom is NOS then in PR uom should be NOS
# but if in Material Request uom KG it can change in PO
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
qty = frappe.db.sql("""select sum(%s) from `tab%s` where %s = %s and
docstatus = 1 and parent != %s""" % (get_qty, curr_doctype, ref_tab_fname, '%s', '%s'),
(ref_tab_dn, curr_parent_name))
qty = qty and flt(qty[0][0]) or 0
# get total qty of ref doctype
#--------------------
max_qty = frappe.db.sql("""select qty from `tab%s` where name = %s
and docstatus = 1""" % (ref_doc_tname, '%s'), ref_tab_dn)
max_qty = max_qty and flt(max_qty[0][0]) or 0
return cstr(qty)+'~~~'+cstr(max_qty)
def check_for_stopped_status(self, doctype, docname):
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
status = 'Stopped'""" % (doctype, '%s'), docname)

View File

@@ -1,5 +1,5 @@
{
"allow_import": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
"docstatus": 0,
@@ -385,6 +385,14 @@
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "advance_paid",
"fieldtype": "Currency",
"label": "Advance Paid",
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "column_break4",
"fieldtype": "Column Break",
@@ -644,12 +652,130 @@
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "recurring_order",
"fieldtype": "Section Break",
"label": "Recurring Order",
"options": "icon-time",
"permlevel": 0
},
{
"fieldname": "column_break",
"fieldtype": "Column Break",
"label": "Column Break",
"permlevel": 0
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.docstatus<2",
"description": "Check if recurring order, uncheck to stop recurring or put proper End Date",
"fieldname": "is_recurring",
"fieldtype": "Check",
"label": "Is Recurring",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"fieldname": "recurring_type",
"fieldtype": "Select",
"label": "Recurring Type",
"no_copy": 1,
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
"permlevel": 0,
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "Start date of current order's period",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "End date of current order's period",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "The day of the month on which auto order will be generated e.g. 05, 28 etc",
"fieldname": "repeat_on_day_of_month",
"fieldtype": "Int",
"label": "Repeat on Day of Month",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which recurring order will be stop",
"fieldname": "end_date",
"fieldtype": "Date",
"label": "End Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
},
{
"fieldname": "column_break83",
"fieldtype": "Column Break",
"label": "Column Break",
"permlevel": 0,
"print_hide": 1
},
{
"depends_on": "eval:doc.is_recurring==1",
"description": "The date on which next invoice will be generated. It is generated on submit.",
"fieldname": "next_date",
"fieldtype": "Date",
"label": "Next Date",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"depends_on": "eval:doc.is_recurring==1",
"fieldname": "recurring_id",
"fieldtype": "Data",
"label": "Recurring Id",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.is_recurring==1",
"description": "Enter email id separated by commas, order will be mailed automatically on particular date",
"fieldname": "notification_email_address",
"fieldtype": "Small Text",
"label": "Notification Email Address",
"no_copy": 1,
"permlevel": 0,
"print_hide": 1
}
],
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-12 05:22:53.496614",
"modified": "2014-11-27 17:27:38.839440",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",

View File

@@ -96,50 +96,45 @@ class PurchaseOrder(BuyingController):
check_list.append(d.prevdoc_docname)
pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
def update_requested_qty(self):
material_request_map = {}
for d in self.get("po_details"):
if d.prevdoc_doctype and d.prevdoc_doctype == "Material Request" and d.prevdoc_detail_docname:
material_request_map.setdefault(d.prevdoc_docname, []).append(d.prevdoc_detail_docname)
def update_bin(self, is_submit, is_stopped = 0):
from erpnext.stock.utils import update_bin
pc_obj = frappe.get_doc('Purchase Common')
for d in self.get('po_details'):
#1. Check if is_stock_item == 'Yes'
if frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes":
# this happens when item is changed from non-stock to stock item
if not d.warehouse:
continue
for mr, mr_item_rows in material_request_map.items():
if mr and mr_item_rows:
mr_obj = frappe.get_doc("Material Request", mr)
ind_qty, po_qty = 0, flt(d.qty) * flt(d.conversion_factor)
if is_stopped:
po_qty = flt(d.qty) > flt(d.received_qty) and \
flt( flt(flt(d.qty) - flt(d.received_qty))*flt(d.conversion_factor)) or 0
if mr_obj.status in ["Stopped", "Cancelled"]:
frappe.throw(_("Material Request {0} is cancelled or stopped").format(mr), frappe.InvalidStatusError)
# No updates in Material Request on Stop / Unstop
if cstr(d.prevdoc_doctype) == 'Material Request' and not is_stopped:
# get qty and pending_qty of prevdoc
curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname',
d.prevdoc_detail_docname, 'Material Request Item',
'Material Request - Purchase Order', self.name)
max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
flt(curr_ref_qty.split('~~~')[0]), 0
mr_obj.update_requested_qty(mr_item_rows)
if flt(qty) + flt(po_qty) > flt(max_qty):
curr_qty = flt(max_qty) - flt(qty)
# special case as there is no restriction
# for Material Request - Purchase Order
curr_qty = curr_qty > 0 and curr_qty or 0
else:
curr_qty = flt(po_qty)
def update_ordered_qty(self, po_item_rows=None):
"""update requested qty (before ordered_qty is updated)"""
from erpnext.stock.utils import get_bin
ind_qty = -flt(curr_qty)
def _update_ordered_qty(item_code, warehouse):
ordered_qty = frappe.db.sql("""
select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
where po_item.item_code=%s and po_item.warehouse=%s
and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
# Update ordered_qty and indented_qty in bin
args = {
"item_code": d.item_code,
"warehouse": d.warehouse,
"ordered_qty": (is_submit and 1 or -1) * flt(po_qty),
"indented_qty": (is_submit and 1 or -1) * flt(ind_qty),
"posting_date": self.transaction_date
}
update_bin(args)
bin_doc = get_bin(item_code, warehouse)
bin_doc.ordered_qty = flt(ordered_qty[0][0]) if ordered_qty else 0
bin_doc.save()
item_wh_list = []
for d in self.get("po_details"):
if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \
and frappe.db.get_value("Item", d.item_code, "is_stock_item") == "Yes" and d.warehouse:
item_wh_list.append([d.item_code, d.warehouse])
for item_code, warehouse in item_wh_list:
_update_ordered_qty(item_code, warehouse)
def check_modified_date(self):
mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s",
@@ -152,20 +147,21 @@ class PurchaseOrder(BuyingController):
def update_status(self, status):
self.check_modified_date()
# step 1:=> Set Status
frappe.db.set(self,'status',cstr(status))
# step 2:=> Update Bin
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
self.update_requested_qty()
self.update_ordered_qty()
# step 3:=> Acknowledge user
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
def on_submit(self):
super(PurchaseOrder, self).on_submit()
purchase_controller = frappe.get_doc("Purchase Common")
self.update_prevdoc_status()
self.update_bin(is_submit = 1, is_stopped = 0)
self.update_requested_qty()
self.update_ordered_qty()
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
self.company, self.grand_total)
@@ -190,8 +186,13 @@ class PurchaseOrder(BuyingController):
throw(_("Purchase Invoice {0} is already submitted").format(", ".join(submitted)))
frappe.db.set(self,'status','Cancelled')
self.update_prevdoc_status()
self.update_bin( is_submit = 0, is_stopped = 0)
# Must be called after updating ordered qty in Material Request
self.update_requested_qty()
self.update_ordered_qty()
pc_obj.update_last_purchase_rate(self, is_submit = 0)
def on_update(self):
@@ -238,10 +239,15 @@ def make_purchase_receipt(source_name, target_doc=None):
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
def postprocess(source, target):
set_missing_values(source, target)
#Get the advance paid Journal Vouchers in Purchase Invoice Advance
target.get_advances()
def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
target.qty = target.amount / flt(obj.rate) if flt(obj.rate) else flt(obj.qty)
target.qty = target.amount / flt(obj.rate) if (flt(obj.rate) and flt(obj.billed_amt)) else flt(obj.qty)
doc = get_mapped_doc("Purchase Order", source_name, {
"Purchase Order": {
@@ -263,6 +269,6 @@ def make_purchase_invoice(source_name, target_doc=None):
"doctype": "Purchase Taxes and Charges",
"add_if_empty": True
}
}, target_doc, set_missing_values)
}, target_doc, postprocess)
return doc

View File

@@ -29,8 +29,7 @@ class TestPurchaseOrder(unittest.TestCase):
frappe.get_doc(pr).insert()
def test_ordered_qty(self):
frappe.db.sql("delete from tabBin")
existing_ordered_qty = self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC")
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
po = frappe.copy_doc(test_records[0]).insert()
@@ -43,8 +42,7 @@ class TestPurchaseOrder(unittest.TestCase):
po.get("po_details")[0].item_code = "_Test Item"
po.submit()
self.assertEquals(frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10)
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 10)
pr = make_purchase_receipt(po.name)
@@ -56,8 +54,9 @@ class TestPurchaseOrder(unittest.TestCase):
pr.insert()
pr.submit()
self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 6.0)
po.load_from_db()
self.assertEquals(po.get("po_details")[0].received_qty, 4)
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
frappe.db.set_value('Item', '_Test Item', 'tolerance', 50)
@@ -68,8 +67,16 @@ class TestPurchaseOrder(unittest.TestCase):
pr1.insert()
pr1.submit()
self.assertEquals(flt(frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 0.0)
po.load_from_db()
self.assertEquals(po.get("po_details")[0].received_qty, 12)
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty)
pr1.load_from_db()
pr1.cancel()
po.load_from_db()
self.assertEquals(po.get("po_details")[0].received_qty, 4)
self.assertEquals(self._get_ordered_qty("_Test Item", "_Test Warehouse - _TC"), existing_ordered_qty + 6)
def test_make_purchase_invoice(self):
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
@@ -107,7 +114,14 @@ class TestPurchaseOrder(unittest.TestCase):
po.get("po_details")[0].qty = 3.4
self.assertRaises(UOMMustBeIntegerError, po.insert)
def test_recurring_order(self):
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
test_recurring_document(self, test_records)
test_dependencies = ["BOM"]
def _get_ordered_qty(self, item_code, warehouse):
return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "ordered_qty"))
test_dependencies = ["BOM", "Item Price"]
test_records = frappe.get_test_records('Purchase Order')

View File

@@ -1,5 +1,6 @@
[
{
"advance_paid": 0.0,
"buying_price_list": "_Test Price List",
"company": "_Test Company",
"conversion_rate": 1.0,
@@ -31,5 +32,39 @@
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
},
{
"advance_paid": 0.0,
"buying_price_list": "_Test Price List",
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"doctype": "Purchase Order",
"fiscal_year": "_Test Fiscal Year 2013",
"grand_total": 5000.0,
"grand_total_import": 5000.0,
"is_subcontracted": "No",
"naming_series": "_T-Purchase Order-",
"net_total": 5000.0,
"po_details": [
{
"base_amount": 5000.0,
"conversion_factor": 1.0,
"description": "_Test Item",
"doctype": "Purchase Order Item",
"item_code": "_Test Item",
"item_name": "_Test Item",
"parentfield": "po_details",
"qty": 10.0,
"rate": 500.0,
"schedule_date": "2013-03-01",
"stock_uom": "_Test UOM",
"uom": "_Test UOM",
"warehouse": "_Test Warehouse - _TC"
}
],
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
}
]
]

View File

@@ -445,7 +445,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.684601",
"modified": "2014-09-09 05:35:36.346557",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@@ -1,8 +1,6 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
{% include 'setup/doctype/contact_control/contact_control.js' %};
cur_frm.cscript.refresh = function(doc, dt, dn) {
cur_frm.cscript.make_dashboard(doc);
@@ -17,15 +15,13 @@ cur_frm.cscript.refresh = function(doc, dt, dn) {
}
else{
unhide_field(['address_html','contact_html']);
// make lists
cur_frm.cscript.make_address(doc,dt,dn);
cur_frm.cscript.make_contact(doc,dt,dn);
erpnext.utils.render_address_and_contact(cur_frm)
cur_frm.communication_view = new frappe.views.CommunicationList({
list: frappe.get_list("Communication", {"supplier": doc.name}),
parent: cur_frm.fields_dict.communication_html.wrapper,
doc: doc
})
});
}
}
@@ -61,45 +57,6 @@ cur_frm.cscript.make_dashboard = function(doc) {
})
}
cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) {
cur_frm.address_list = new frappe.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 5,
new_doctype: "Address",
get_query: function() {
return "select name, address_type, address_line1, address_line2, city, state, country, pincode, fax, email_id, phone, is_primary_address, is_shipping_address from tabAddress where supplier='" +
cur_frm.doc.name.replace(/'/g, "\\'") + "' and docstatus != 2 order by is_primary_address desc"
},
as_dict: 1,
no_results_message: __('No addresses created'),
render_row: cur_frm.cscript.render_address_row,
});
// note: render_address_row is defined in contact_control.js
}
cur_frm.address_list.run();
}
cur_frm.cscript.make_contact = function() {
if(!cur_frm.contact_list) {
cur_frm.contact_list = new frappe.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 5,
new_doctype: "Contact",
get_query: function() {
return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where supplier='" +
cur_frm.doc.name.replace(/'/g, "\\'") + "' and docstatus != 2 order by is_primary_contact desc"
},
as_dict: 1,
no_results_message: __('No contacts created'),
render_row: cur_frm.cscript.render_contact_row,
});
// note: render_contact_row is defined in contact_control.js
}
cur_frm.contact_list.run();
}
cur_frm.fields_dict['default_price_list'].get_query = function(doc, cdt, cdn) {
return{
filters:{'buying': 1}

View File

@@ -186,12 +186,20 @@
],
"icon": "icon-user",
"idx": 1,
"modified": "2014-08-26 04:55:32.004458",
"modified": "2014-09-10 17:53:09.286715",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
"owner": "Administrator",
"permissions": [
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User"
},
{
"amend": 0,
"create": 0,
@@ -201,7 +209,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User",
"role": "Purchase Manager",
"submit": 0,
"write": 0
},
@@ -224,11 +232,27 @@
"read": 1,
"role": "Material User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Material Manager"
},
{
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Accounts User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager"
}
],
"search_fields": "supplier_name,supplier_type",

View File

@@ -9,10 +9,14 @@ from frappe.utils import cint
from frappe import msgprint, _
from frappe.model.naming import make_autoname
from erpnext.accounts.party import create_party_account
from erpnext.utilities.address_and_contact import load_address_and_contact
from erpnext.utilities.transaction_base import TransactionBase
class Supplier(TransactionBase):
def onload(self):
"""Load address and contacts in `__onload`"""
load_address_and_contact(self, "supplier")
def autoname(self):
supp_master_name = frappe.defaults.get_global_default('supp_master_name')

View File

@@ -4,5 +4,11 @@
"doctype": "Supplier",
"supplier_name": "_Test Supplier",
"supplier_type": "_Test Supplier Type"
},
{
"company": "_Test Company",
"doctype": "Supplier",
"supplier_name": "_Test Supplier 1",
"supplier_type": "_Test Supplier Type"
}
]
]

View File

@@ -331,7 +331,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.976906",
"modified": "2014-09-09 05:35:36.623995",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",

View File

@@ -5,12 +5,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:17.358554",
"modified_by": "Administrator",
"modified": "2014-09-11 08:53:17.358554",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Addresses and Contacts",
"owner": "Administrator",
"query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
"query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as \"Contact Name::180\",\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
"ref_doctype": "Supplier",
"report_name": "Supplier Addresses and Contacts",
"report_type": "Query Report"

View File

@@ -61,6 +61,11 @@ def get_data():
"name": "Period Closing Voucher",
"description": _("Close Balance Sheet and book Profit or Loss.")
},
{
"type": "doctype",
"name": "Payment Tool",
"description": _("Create Payment Entries against Orders or Invoices.")
},
]
},
{

View File

@@ -135,12 +135,6 @@ def get_data():
"name": "Item-wise Purchase History",
"doctype": "Item"
},
{
"type": "report",
"is_query_report": True,
"name": "Item-wise Last Purchase Rate",
"doctype": "Item"
},
{
"type": "report",
"is_query_report": True,

View File

@@ -26,6 +26,11 @@ def get_data():
"name": "Purchase Receipt",
"description": _("Goods received from Suppliers."),
},
{
"type": "doctype",
"name": "Installation Note",
"description": _("Installation record for a Serial No.")
},
{
"type": "doctype",
"name": "Item",
@@ -57,11 +62,6 @@ def get_data():
"name": "Stock Reconciliation",
"description": _("Upload stock balance via csv.")
},
{
"type": "doctype",
"name": "Installation Note",
"description": _("Installation record for a Serial No.")
},
{
"type": "doctype",
"name": "Packing Slip",
@@ -142,10 +142,10 @@ def get_data():
"doctype": "Item",
},
{
"type": "page",
"name": "stock-balance",
"label": _("Stock Balance"),
"icon": "icon-table",
"type": "report",
"is_query_report": True,
"name": "Stock Balance",
"doctype": "Warehouse"
},
{
"type": "report",
@@ -170,7 +170,7 @@ def get_data():
"name": "stock-analytics",
"label": _("Stock Analytics"),
"icon": "icon-bar-chart"
},
}
]
},
{
@@ -222,12 +222,6 @@ def get_data():
"name": "Batch-Wise Balance History",
"doctype": "Batch"
},
{
"type": "report",
"is_query_report": True,
"name": "Warehouse-Wise Stock Balance",
"doctype": "Warehouse"
},
{
"type": "report",
"is_query_report": True,

View File

@@ -4,12 +4,11 @@
from __future__ import unicode_literals
import frappe
from frappe import _, throw
from frappe.utils import add_days, cint, cstr, today, date_diff, flt, getdate, nowdate, \
get_first_day, get_last_day
from frappe.model.naming import make_autoname
from frappe.utils import cint, today, flt
from erpnext.setup.utils import get_company_currency, get_exchange_rate
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
import json
class AccountsController(TransactionBase):
@@ -24,6 +23,24 @@ class AccountsController(TransactionBase):
self.validate_for_freezed_account()
if self.meta.get_field("is_recurring"):
validate_recurring_document(self)
def on_submit(self):
if self.meta.get_field("is_recurring"):
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
def on_update_after_submit(self):
if self.meta.get_field("is_recurring"):
validate_recurring_document(self)
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
def before_recurring(self):
self.fiscal_year = None
for fieldname in ("due_date", "aging_date"):
if self.meta.get_field(fieldname):
self.set(fieldname, None)
def set_missing_values(self, for_validate=False):
for fieldname in ["posting_date", "transaction_date"]:
if not self.get(fieldname) and self.meta.get_field(fieldname):
@@ -102,6 +119,10 @@ class AccountsController(TransactionBase):
item.get(fieldname) is None and value is not None:
item.set(fieldname, value)
if fieldname == "cost_center" and item.meta.get_field("cost_center") \
and not item.get("cost_center") and value is not None:
item.set(fieldname, value)
if ret.get("pricing_rule"):
for field in ["base_price_list_rate", "price_list_rate",
"discount_percentage", "base_rate", "rate"]:
@@ -274,7 +295,7 @@ class AccountsController(TransactionBase):
self.precision("tax_amount", tax))
def adjust_discount_amount_loss(self, tax):
discount_amount_loss = self.grand_total - flt(self.discount_amount) - tax.total
discount_amount_loss = self.grand_total - flt(self.base_discount_amount) - tax.total
tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount +
discount_amount_loss, self.precision("tax_amount", tax))
tax.total = flt(tax.total + discount_amount_loss, self.precision("total", tax))
@@ -362,19 +383,29 @@ class AccountsController(TransactionBase):
frappe.db.sql("""delete from `tab%s` where parentfield=%s and parent = %s
and ifnull(allocated_amount, 0) = 0""" % (childtype, '%s', '%s'), (parentfield, self.name))
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr):
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr, against_order_field):
so_list = list(set([d.get(against_order_field) for d in self.get("entries") if d.get(against_order_field)]))
cond = ""
if so_list:
cond = "or (ifnull(t2.%s, '') in (%s))" % ("against_" + against_order_field, ', '.join(['%s']*len(so_list)))
res = frappe.db.sql("""
select
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no, `against_%s` as against_order
from
`tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
where
t1.name = t2.parent and t2.account = %s and t2.is_advance = 'Yes' and t1.docstatus = 1
and ifnull(t2.against_voucher, '') = ''
and ifnull(t2.against_invoice, '') = ''
and ifnull(t2.against_jv, '') = ''
and ((
ifnull(t2.against_voucher, '') = ''
and ifnull(t2.against_invoice, '') = ''
and ifnull(t2.against_jv, '') = ''
and ifnull(t2.against_sales_order, '') = ''
and ifnull(t2.against_purchase_order, '') = ''
) %s)
order by t1.posting_date""" %
(dr_or_cr, '%s'), account_head, as_dict=1)
(dr_or_cr, against_order_field, '%s', cond),
tuple([account_head] + so_list), as_dict= True)
self.set(parentfield, [])
for d in res:
@@ -384,9 +415,36 @@ class AccountsController(TransactionBase):
"jv_detail_no": d.jv_detail_no,
"remarks": d.remark,
"advance_amount": flt(d.amount),
"allocate_amount": 0
"allocated_amount": flt(d.amount) if d.against_order else 0
})
def validate_advance_jv(self, advance_table_fieldname, against_order_field):
order_list = list(set([d.get(against_order_field) for d in self.get("entries") if d.get(against_order_field)]))
if order_list:
account = self.get("debit_to" if self.doctype=="Sales Invoice" else "credit_to")
jv_against_order = frappe.db.sql("""select parent, %s as against_order
from `tabJournal Voucher Detail`
where docstatus=1 and account=%s and ifnull(is_advance, 'No') = 'Yes'
and ifnull(against_sales_order, '') in (%s)
group by parent, against_sales_order""" %
("against_" + against_order_field, '%s', ', '.join(['%s']*len(order_list))),
tuple([account] + order_list), as_dict=1)
if jv_against_order:
order_jv_map = {}
for d in jv_against_order:
order_jv_map.setdefault(d.against_order, []).append(d.parent)
advance_jv_against_si = [d.journal_voucher for d in self.get(advance_table_fieldname)]
for order, jv_list in order_jv_map.items():
for jv in jv_list:
if not advance_jv_against_si or jv not in advance_jv_against_si:
frappe.msgprint(_("Journal Voucher {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.")
.format(jv, order))
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
from erpnext.controllers.status_updater import get_tolerance_for
item_tolerance = {}
@@ -413,8 +471,7 @@ class AccountsController(TransactionBase):
max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100)
if total_billed_amt - max_allowed_amt > 0.01:
reduce_by = total_billed_amt - max_allowed_amt
frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt))
frappe.throw(_("Cannot overbill for Item {0} in row {1} more than {2}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt))
def get_company_default(self, fieldname):
from erpnext.accounts.utils import get_company_default
@@ -430,6 +487,32 @@ class AccountsController(TransactionBase):
return stock_items
def set_total_advance_paid(self):
if self.doctype == "Sales Order":
dr_or_cr = "credit"
against_field = "against_sales_order"
else:
dr_or_cr = "debit"
against_field = "against_purchase_order"
advance_paid = frappe.db.sql("""
select
sum(ifnull({dr_or_cr}, 0))
from
`tabJournal Voucher Detail`
where
{against_field} = %s and docstatus = 1 and is_advance = "Yes" """.format(dr_or_cr=dr_or_cr, \
against_field=against_field), self.name)
if advance_paid:
advance_paid = flt(advance_paid[0][0], self.precision("advance_paid"))
if flt(self.grand_total) >= advance_paid:
frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid)
else:
frappe.throw(_("Total advance ({0}) against Order {1} cannot be greater \
than the Grand Total ({2})")
.format(advance_paid, self.name, self.grand_total))
@property
def company_abbr(self):
if not hasattr(self, "_abbr"):

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe.utils import flt, rounded
from erpnext.setup.utils import get_company_currency
from erpnext.accounts.party import get_party_details
@@ -90,8 +91,7 @@ class BuyingController(StockController):
item.rate = flt(item.price_list_rate * (1.0 - (item.discount_percentage / 100.0)),
self.precision("rate", item))
item.amount = flt(item.rate * item.qty,
self.precision("amount", item))
item.amount = flt(item.rate * item.qty, self.precision("amount", item))
item.item_tax_amount = 0.0;
self._set_in_company_currency(item, "amount", "base_amount")
@@ -109,20 +109,15 @@ class BuyingController(StockController):
self.round_floats_in(self, ["net_total", "net_total_import"])
def calculate_totals(self):
self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist
else self.net_total, self.precision("grand_total"))
self.grand_total_import = flt(self.grand_total / self.conversion_rate,
self.precision("grand_total_import"))
self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist else self.net_total)
self.total_tax = flt(self.grand_total - self.net_total,
self.precision("total_tax"))
self.total_tax = flt(self.grand_total - self.net_total, self.precision("total_tax"))
self.grand_total = flt(self.grand_total, self.precision("grand_total"))
if self.meta.get_field("rounded_total"):
self.rounded_total = rounded(self.grand_total)
if self.meta.get_field("rounded_total_import"):
self.rounded_total_import = rounded(self.grand_total_import)
if self.meta.get_field("other_charges_added"):
self.other_charges_added = flt(sum([flt(d.tax_amount) for d in self.tax_doclist
if d.add_deduct_tax=="Add" and d.category in ["Valuation and Total", "Total"]]),
@@ -133,6 +128,14 @@ class BuyingController(StockController):
if d.add_deduct_tax=="Deduct" and d.category in ["Valuation and Total", "Total"]]),
self.precision("other_charges_deducted"))
self.grand_total_import = flt(self.grand_total / self.conversion_rate) \
if (self.other_charges_added or self.other_charges_deducted) else self.net_total_import
self.grand_total_import = flt(self.grand_total_import, self.precision("grand_total_import"))
if self.meta.get_field("rounded_total_import"):
self.rounded_total_import = rounded(self.grand_total_import)
if self.meta.get_field("other_charges_added_import"):
self.other_charges_added_import = flt(self.other_charges_added /
self.conversion_rate, self.precision("other_charges_added_import"))
@@ -255,8 +258,6 @@ class BuyingController(StockController):
rm.required_qty = required_qty
rm.conversion_factor = item.conversion_factor
rm.rate = bom_item.rate
rm.amount = required_qty * flt(bom_item.rate)
rm.idx = rm_supplied_idx
if self.doctype == "Purchase Receipt":
@@ -267,7 +268,25 @@ class BuyingController(StockController):
rm_supplied_idx += 1
raw_materials_cost += required_qty * flt(bom_item.rate)
# get raw materials rate
if self.doctype == "Purchase Receipt":
from erpnext.stock.utils import get_incoming_rate
rm.rate = get_incoming_rate({
"item_code": bom_item.item_code,
"warehouse": self.supplier_warehouse,
"posting_date": self.posting_date,
"posting_time": self.posting_time,
"qty": -1 * required_qty,
"serial_no": rm.serial_no
})
if not rm.rate:
from erpnext.stock.stock_ledger import get_valuation_rate
rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse)
else:
rm.rate = bom_item.rate
rm.amount = required_qty * flt(rm.rate)
raw_materials_cost += flt(rm.amount)
if self.doctype == "Purchase Receipt":
item.rm_supp_cost = raw_materials_cost

View File

@@ -2,15 +2,28 @@ from __future__ import unicode_literals
import frappe
import frappe.utils
import frappe.defaults
from frappe.utils import cint, cstr, getdate, nowdate, get_first_day, get_last_day
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
get_first_day, get_last_day, comma_and
from frappe.model.naming import make_autoname
from frappe import _, msgprint, throw
from erpnext.accounts.party import get_party_account, get_due_date, get_party_details
from frappe.model.mapper import get_mapped_doc
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
date_field_map = {
"Sales Order": "transaction_date",
"Sales Invoice": "posting_date",
"Purchase Order": "transaction_date",
"Purchase Invoice": "posting_date"
}
def create_recurring_documents():
manage_recurring_documents("Sales Order")
manage_recurring_documents("Sales Invoice")
manage_recurring_documents("Purchase Order")
manage_recurring_documents("Purchase Invoice")
def manage_recurring_documents(doctype, next_date=None, commit=True):
"""
@@ -19,10 +32,7 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
"""
next_date = next_date or nowdate()
if doctype == "Sales Order":
date_field = "transaction_date"
elif doctype == "Sales Invoice":
date_field = "posting_date"
date_field = date_field_map[doctype]
recurring_documents = frappe.db.sql("""select name, recurring_id
from `tab{}` where ifnull(is_recurring, 0)=1
@@ -36,6 +46,9 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
% (doctype, date_field, '%s', '%s'), (next_date, recurring_id)):
try:
ref_wrapper = frappe.get_doc(doctype, ref_document)
if hasattr(ref_wrapper, "before_recurring"):
ref_wrapper.before_recurring()
new_document_wrapper = make_new_document(ref_wrapper, date_field, next_date)
send_notification(new_document_wrapper)
if commit:
@@ -48,7 +61,8 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
frappe.db.sql("update `tab%s` \
set is_recurring = 0 where name = %s" % (doctype, '%s'),
(ref_document))
notify_errors(ref_document, doctype, ref_wrapper.customer, ref_wrapper.owner)
notify_errors(ref_document, doctype, ref_wrapper.get("customer") or ref_wrapper.get("supplier"),
ref_wrapper.owner)
frappe.db.commit()
exception_list.append(frappe.get_traceback())
@@ -110,12 +124,9 @@ def send_notification(new_rv):
frappe.sendmail(new_rv.notification_email_address,
subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
attachments = [{
"fname": new_rv.name + ".pdf",
"fcontent": frappe.get_print_format(new_rv.doctype, new_rv.name, as_pdf=True)
}])
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name)])
def notify_errors(doc, doctype, customer, owner):
def notify_errors(doc, doctype, party, owner):
from frappe.utils.user import get_system_managers
recipients = get_system_managers(only_name=True)
@@ -124,7 +135,7 @@ def notify_errors(doc, doctype, customer, owner):
message = frappe.get_template("templates/emails/recurring_document_failed.html").render({
"type": doctype,
"name": doc,
"customer": customer
"party": party
}))
assign_task_to_owner(doc, doctype, "Recurring Invoice Failed", recipients)
@@ -152,18 +163,18 @@ def validate_recurring_document(doc):
elif not (doc.from_date and doc.to_date):
throw(_("Period From and Period To dates mandatory for recurring %s") % doc.doctype)
def convert_to_recurring(doc, autoname, posting_date):
if doc.is_recurring:
if not doc.recurring_id:
frappe.db.set(doc, "recurring_id",
make_autoname(autoname))
#
def convert_to_recurring(doc, posting_date):
if doc.is_recurring:
if not doc.recurring_id:
frappe.db.set(doc, "recurring_id", doc.name)
set_next_date(doc, posting_date)
set_next_date(doc, posting_date)
elif doc.recurring_id:
frappe.db.sql("""update `tab%s`
set is_recurring = 0
where recurring_id = %s""" % (doc.doctype, '%s'), (doc.recurring_id))
elif doc.recurring_id:
frappe.db.sql("""update `tab%s` set is_recurring = 0
where recurring_id = %s""" % (doc.doctype, '%s'), (doc.recurring_id))
#
def validate_notification_email_id(doc):
if doc.notification_email_address:

View File

@@ -216,33 +216,38 @@ class SellingController(StockController):
self.round_floats_in(self, ["net_total", "net_total_export"])
def calculate_totals(self):
self.grand_total = flt(self.tax_doclist and \
self.tax_doclist[-1].total or self.net_total, self.precision("grand_total"))
self.grand_total_export = flt(self.grand_total / self.conversion_rate,
self.precision("grand_total_export"))
self.grand_total = flt(self.tax_doclist[-1].total if self.tax_doclist else self.net_total)
self.other_charges_total = flt(self.grand_total - self.net_total,
self.precision("other_charges_total"))
self.other_charges_total = flt(self.grand_total - self.net_total, self.precision("other_charges_total"))
self.other_charges_total_export = flt(self.grand_total_export -
self.net_total_export + flt(self.discount_amount),
self.precision("other_charges_total_export"))
self.grand_total_export = flt(self.grand_total / self.conversion_rate) \
if (self.other_charges_total or self.discount_amount) else self.net_total_export
self.other_charges_total_export = flt(self.grand_total_export - self.net_total_export +
flt(self.discount_amount), self.precision("other_charges_total_export"))
self.grand_total = flt(self.grand_total, self.precision("grand_total"))
self.grand_total_export = flt(self.grand_total_export, self.precision("grand_total_export"))
self.rounded_total = rounded(self.grand_total)
self.rounded_total_export = rounded(self.grand_total_export)
def apply_discount_amount(self):
if self.discount_amount:
self.base_discount_amount = flt(self.discount_amount * self.conversion_rate, self.precision("base_discount_amount"))
grand_total_for_discount_amount = self.get_grand_total_for_discount_amount()
if grand_total_for_discount_amount:
# calculate item amount after Discount Amount
for item in self.item_doclist:
distributed_amount = flt(self.discount_amount) * item.base_amount / grand_total_for_discount_amount
distributed_amount = flt(self.base_discount_amount) * item.base_amount / grand_total_for_discount_amount
item.base_amount = flt(item.base_amount - distributed_amount, self.precision("base_amount", item))
self.discount_amount_applied = True
self._calculate_taxes_and_totals()
else:
self.base_discount_amount = 0
def get_grand_total_for_discount_amount(self):
actual_taxes_dict = {}

View File

@@ -8,7 +8,7 @@ from frappe import msgprint, _
import frappe.defaults
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries
from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map
class StockController(AccountsController):
def make_gl_entries(self, repost_future_gle=True):
@@ -16,20 +16,20 @@ class StockController(AccountsController):
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
warehouse_account = self.get_warehouse_account()
warehouse_account = get_warehouse_account()
if self.docstatus==1:
gl_entries = self.get_gl_entries(warehouse_account)
make_gl_entries(gl_entries)
if repost_future_gle:
items, warehouse_account = self.get_items_and_warehouse_accounts(warehouse_account)
update_gl_entries_after(self.posting_date, self.posting_time,
warehouse_account, items)
items, warehouses = self.get_items_and_warehouses()
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items,
warehouse_account)
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
default_cost_center=None):
from erpnext.accounts.general_ledger import process_gl_map
if not warehouse_account:
warehouse_account = get_warehouse_account()
@@ -88,10 +88,8 @@ class StockController(AccountsController):
return details
def get_items_and_warehouse_accounts(self, warehouse_account=None):
def get_items_and_warehouses(self):
items, warehouses = [], []
if not warehouse_account:
warehouse_account = get_warehouse_account()
if hasattr(self, "fname"):
item_doclist = self.get(self.fname)
@@ -117,86 +115,17 @@ class StockController(AccountsController):
if d.get("t_warehouse") and d.t_warehouse not in warehouses:
warehouses.append(d.t_warehouse)
warehouse_account = {wh: warehouse_account[wh] for wh in warehouses
if warehouse_account.get(wh)}
return items, warehouse_account
return items, warehouses
def get_stock_ledger_details(self):
stock_ledger = {}
for sle in frappe.db.sql("""select warehouse, stock_value_difference, voucher_detail_no
for sle in frappe.db.sql("""select warehouse, stock_value_difference,
voucher_detail_no, item_code, posting_date, actual_qty
from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""",
(self.doctype, self.name), as_dict=True):
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
return stock_ledger
def get_warehouse_account(self):
warehouse_account = dict(frappe.db.sql("""select master_name, name from tabAccount
where account_type = 'Warehouse' and ifnull(master_name, '') != ''"""))
return warehouse_account
def update_gl_entries_after(self, warehouse_account=None):
future_stock_vouchers = self.get_future_stock_vouchers()
gle = self.get_voucherwise_gl_entries(future_stock_vouchers)
if not warehouse_account:
warehouse_account = self.get_warehouse_account()
for voucher_type, voucher_no in future_stock_vouchers:
existing_gle = gle.get((voucher_type, voucher_no), [])
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
if expected_gle:
matched = True
if existing_gle:
for entry in expected_gle:
for e in existing_gle:
if entry.account==e.account \
and entry.against_account==e.against_account\
and entry.cost_center==e.cost_center:
if entry.debit != e.debit or entry.credit != e.credit:
matched = False
break
else:
matched = False
if not matched:
self.delete_gl_entries(voucher_type, voucher_no)
voucher_obj.make_gl_entries(repost_future_gle=False)
else:
self.delete_gl_entries(voucher_type, voucher_no)
def get_future_stock_vouchers(self):
condition = ""
item_list = []
if getattr(self, "fname", None):
item_list = [d.item_code for d in self.get(self.fname)]
if item_list:
condition = "and item_code in ({})".format(", ".join(["%s"] * len(item_list)))
future_stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
from `tabStock Ledger Entry` sle
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
order by timestamp(sle.posting_date, sle.posting_time) asc, name asc""".format(
condition=condition), tuple([self.posting_date, self.posting_date] + item_list),
as_list=True)
return future_stock_vouchers
def get_voucherwise_gl_entries(self, future_stock_vouchers):
gl_entries = {}
if future_stock_vouchers:
for d in frappe.db.sql("""select * from `tabGL Entry`
where posting_date >= %s and voucher_no in (%s)""" %
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
tuple([self.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
return gl_entries
def delete_gl_entries(self, voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
def make_adjustment_entry(self, expected_gle, voucher_obj):
from erpnext.accounts.utils import get_stock_and_account_difference
account_list = [d.account for d in expected_gle]
@@ -238,7 +167,7 @@ class StockController(AccountsController):
else:
is_expense_account = frappe.db.get_value("Account",
item.get("expense_account"), "report_type")=="Profit and Loss"
if self.doctype not in ("Purchase Receipt", "Stock Reconciliation") and not is_expense_account:
if self.doctype not in ("Purchase Receipt", "Stock Reconciliation", "Stock Entry") and not is_expense_account:
frappe.throw(_("Expense / Difference account ({0}) must be a 'Profit or Loss' account")
.format(item.get("expense_account")))
if is_expense_account and not item.get("cost_center"):
@@ -246,7 +175,7 @@ class StockController(AccountsController):
_(self.doctype), self.name, item.get("item_code")))
def get_sl_entries(self, d, args):
sl_dict = {
sl_dict = frappe._dict({
"item_code": d.get("item_code", None),
"warehouse": d.get("warehouse", None),
"posting_date": self.posting_date,
@@ -263,14 +192,14 @@ class StockController(AccountsController):
"serial_no": d.get("serial_no"),
"project": d.get("project_name"),
"is_cancelled": self.docstatus==2 and "Yes" or "No"
}
})
sl_dict.update(args)
return sl_dict
def make_sl_entries(self, sl_entries, is_amended=None):
def make_sl_entries(self, sl_entries, is_amended=None, allow_negative_stock=False):
from erpnext.stock.stock_ledger import make_sl_entries
make_sl_entries(sl_entries, is_amended)
make_sl_entries(sl_entries, is_amended, allow_negative_stock)
def make_gl_entries_on_cancel(self):
if frappe.db.sql("""select name from `tabGL Entry` where voucher_type=%s
@@ -287,15 +216,16 @@ class StockController(AccountsController):
return serialized_items
def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None):
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None):
def _delete_gl_entries(voucher_type, voucher_no):
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
if not warehouse_account:
warehouse_account = get_warehouse_account()
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time,
warehouse_account, for_items)
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
for voucher_type, voucher_no in future_stock_vouchers:
@@ -315,13 +245,13 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle):
for entry in expected_gle:
for e in existing_gle:
if entry.account==e.account and entry.against_account==e.against_account \
and entry.cost_center==e.cost_center \
and (not entry.cost_center or not e.cost_center or entry.cost_center==e.cost_center) \
and (entry.debit != e.debit or entry.credit != e.credit):
matched = False
break
return matched
def get_future_stock_vouchers(posting_date, posting_time, warehouse_account=None, for_items=None):
def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
future_stock_vouchers = []
values = []
@@ -330,9 +260,9 @@ def get_future_stock_vouchers(posting_date, posting_time, warehouse_account=None
condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
values += for_items
if warehouse_account:
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(warehouse_account.keys())))
values += warehouse_account.keys()
if for_warehouses:
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
values += for_warehouses
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
from `tabStock Ledger Entry` sle

View File

@@ -2,12 +2,8 @@
# License: GNU General Public License v3. See license.txt
import frappe
import unittest, json, copy
from frappe.utils import flt
import frappe.permissions
from erpnext.accounts.utils import get_stock_and_account_difference
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
from erpnext.controllers.recurring_document import date_field_map
def test_recurring_document(obj, test_records):
from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate, add_days
@@ -27,20 +23,11 @@ def test_recurring_document(obj, test_records):
"to_date": get_last_day(today)
})
if base_doc.doctype == "Sales Order":
base_doc.update({
"transaction_date": today,
"delivery_date": add_days(today, 15)
})
elif base_doc.doctype == "Sales Invoice":
base_doc.update({
"posting_date": today
})
date_field = date_field_map[base_doc.doctype]
base_doc.set(date_field, today)
if base_doc.doctype == "Sales Order":
date_field = "transaction_date"
elif base_doc.doctype == "Sales Invoice":
date_field = "posting_date"
base_doc.set("delivery_date", add_days(today, 15))
# monthly
doc1 = frappe.copy_doc(base_doc)
@@ -128,7 +115,7 @@ def _test_recurring_document(obj, base_doc, date_field, first_and_last_day):
next_date = get_next_date(base_doc.get(date_field), no_of_months,
base_doc.repeat_on_day_of_month)
manage_recurring_documents(base_doc.doctype, next_date=next_date, commit=False)
recurred_documents = frappe.db.sql("""select name from `tab%s`

View File

@@ -16,10 +16,10 @@ def get_columns(filters, trans):
# get conditions for grouping filter cond
group_by_cols = group_wise_column(filters.get("group_by"))
columns = based_on_details["based_on_cols"] + period_cols + ["Total(Qty):Float:120", "Total(Amt):Currency:120"]
columns = based_on_details["based_on_cols"] + period_cols + [_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
if group_by_cols:
columns = based_on_details["based_on_cols"] + group_by_cols + period_cols + \
["Total(Qty):Float:120", "Total(Amt):Currency:120"]
[_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
conditions = {"based_on_select": based_on_details["based_on_select"], "period_wise_select": period_select,
"columns": columns, "group_by": based_on_details["based_on_group_by"], "grbc": group_by_cols, "trans": trans,
@@ -130,8 +130,8 @@ def period_wise_columns_query(filters, trans):
get_period_wise_columns(dt, filters.get("period"), pwc)
query_details = get_period_wise_query(dt, trans_date, query_details)
else:
pwc = [filters.get("fiscal_year") + " (Qty):Float:120",
filters.get("fiscal_year") + " (Amt):Currency:120"]
pwc = [_(filters.get("fiscal_year")) + " ("+_("Qty") + "):Float:120",
_(filters.get("fiscal_year")) + " ("+ _("Amt") + "):Currency:120"]
query_details = " SUM(t2.qty), SUM(t2.base_amount),"
query_details += 'SUM(t2.qty), SUM(t2.base_amount)'
@@ -139,11 +139,11 @@ def period_wise_columns_query(filters, trans):
def get_period_wise_columns(bet_dates, period, pwc):
if period == 'Monthly':
pwc += [get_mon(bet_dates[0]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + " (Amt):Currency:120"]
pwc += [_(get_mon(bet_dates[0])) + " (" + _("Qty") + "):Float:120",
_(get_mon(bet_dates[0])) + " (" + _("Amt") + "):Currency:120"]
else:
pwc += [get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Amt):Currency:120"]
pwc += [_(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Qty") + "):Float:120",
_(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Amt") + "):Currency:120"]
def get_period_wise_query(bet_dates, trans_date, query_details):
query_details += """SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.qty, NULL)),

View File

@@ -20,7 +20,7 @@ frappe.pages['activity'].onload = function(wrapper) {
});
list.run();
wrapper.appframe.set_title_right("Refresh", function() { list.run(); });
wrapper.appframe.set_title_right(__("Refresh"), function() { list.run(); });
// Build Report Button
if(frappe.boot.user.can_get_report.indexOf("Feed")!=-1) {

View File

@@ -4,7 +4,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "4.3.0"
app_version = "4.21.4"
error_report_email = "support@erpnext.com"
@@ -47,8 +47,8 @@ doc_events = {
"on_update": "erpnext.home.make_comment_feed"
},
"Stock Entry": {
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_qty",
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_qty"
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
"on_cancel": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty"
},
"User": {
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",

File diff suppressed because it is too large Load Diff

View File

@@ -200,7 +200,7 @@ def validate_employee_role(doc, method):
# called via User hook
if "Employee" in [d.role for d in doc.get("user_roles")]:
if not frappe.db.get_value("Employee", {"user_id": doc.name}):
frappe.msgprint("Please set User ID field in an Employee record to set Employee Role")
frappe.msgprint(_("Please set User ID field in an Employee record to set Employee Role"))
doc.get("user_roles").remove(doc.get("user_roles", {"role": "Employee"})[0])
def update_user_permissions(doc, method):

View File

@@ -1,9 +1,21 @@
{
"autoname": "EXP.######",
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:14",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"default": "EXP",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"no_copy": 1,
"options": "EXP",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"reqd": 1
},
{
"default": "Draft",
"depends_on": "eval:!doc.__islocal",
@@ -190,7 +202,7 @@
"icon": "icon-money",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-27 07:08:48.454580",
"modified": "2014-11-24 18:25:53.038826",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",

View File

@@ -33,7 +33,7 @@ cur_frm.cscript.refresh = function(doc, dt, dn) {
cur_frm.set_intro(__("You are the Leave Approver for this record. Please Update the 'Status' and Save"));
cur_frm.toggle_enable("status", true);
} else {
cur_frm.set_intro(__("This Leave Application is pending approval. Only the Leave Apporver can update status."))
cur_frm.set_intro(__("This Leave Application is pending approval. Only the Leave Approver can update status."))
cur_frm.toggle_enable("status", false);
if(!doc.__islocal) {
cur_frm.frm_head.appframe.set_title_right("");
@@ -104,9 +104,32 @@ cur_frm.cscript.calculate_total_days = function(doc, dt, dn) {
if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
else{
// server call is done to include holidays in leave days calculations
return get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_total_leave_days',
args: {leave_app: doc},
callback: function(response) {
if (response && response.message) {
cur_frm.set_value('total_leave_days', response.message.total_leave_days);
}
}
});
}
}
}
cur_frm.fields_dict.employee.get_query = erpnext.queries.employee;
frappe.ui.form.on("Leave Application", "leave_approver", function(frm) {
frappe.call({
"method": "frappe.client.get",
args: {
doctype: "User",
name: frm.doc.leave_approver
},
callback: function (data) {
frappe.model.set_value(frm.doctype, frm.docname, "leave_approver_name",
data.message.first_name
+ (data.message.last_name ? (" " + data.message.last_name) : ""))
}
})
})

View File

@@ -24,6 +24,13 @@
"options": "User",
"permlevel": 0
},
{
"fieldname": "leave_approver_name",
"fieldtype": "Read Only",
"label": "Leave Approver Name",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "leave_type",
"fieldtype": "Link",
@@ -158,6 +165,7 @@
"reqd": 1
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -183,7 +191,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 3,
"modified": "2014-08-28 03:32:38.865202",
"modified": "2014-12-09 16:33:29.626849",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",

View File

@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
import frappe, json
from frappe import _
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_url_to_form, \
@@ -77,26 +77,10 @@ class LeaveApplication(Document):
LeaveDayBlockedError)
def get_holidays(self):
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2, `tabEmployee` e1
where e1.name = %s and h1.parent = h2.name and e1.holiday_list = h2.name
and h1.holiday_date between %s and %s""", (self.employee, self.from_date, self.to_date))
if not tot_hol:
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2
where h1.parent = h2.name and h1.holiday_date between %s and %s
and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""",
(self.from_date, self.to_date, self.fiscal_year))
return tot_hol and flt(tot_hol[0][0]) or 0
return get_holidays(self)
def get_total_leave_days(self):
"""Calculates total leave days based on input and holidays"""
ret = {'total_leave_days' : 0.5}
if not self.half_day:
tot_days = date_diff(self.to_date, self.from_date) + 1
holidays = self.get_holidays()
ret = {
'total_leave_days' : flt(tot_days)-flt(holidays)
}
return ret
return get_total_leave_days(self)
def validate_to_date(self):
if self.from_date and self.to_date and \
@@ -216,6 +200,35 @@ class LeaveApplication(Document):
post(**{"txt": args.message, "contact": args.message_to, "subject": args.subject,
"notify": cint(self.follow_via_email)})
def get_holidays(leave_app):
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2, `tabEmployee` e1
where e1.name = %s and h1.parent = h2.name and e1.holiday_list = h2.name
and h1.holiday_date between %s and %s""", (leave_app.employee, leave_app.from_date,
leave_app.to_date))[0][0]
# below line is needed. If an employee hasn't been assigned with any holiday list then above will return 0 rows.
if not tot_hol:
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2
where h1.parent = h2.name and h1.holiday_date between %s and %s
and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""",
(leave_app.from_date, leave_app.to_date, leave_app.fiscal_year))[0][0]
return tot_hol
@frappe.whitelist()
def get_total_leave_days(leave_app):
# Parse Leave Application if neccessary
if isinstance(leave_app, str) or isinstance(leave_app, unicode):
leave_app = frappe.get_doc(json.loads(leave_app))
"""Calculates total leave days based on input and holidays"""
ret = {'total_leave_days' : 0.5}
if not leave_app.half_day:
tot_days = date_diff(leave_app.to_date, leave_app.from_date) + 1
holidays = leave_app.get_holidays()
ret = {
'total_leave_days' : flt(tot_days)-flt(holidays)
}
return ret
@frappe.whitelist()
def get_leave_balance(employee, leave_type, fiscal_year):
leave_all = frappe.db.sql("""select total_leaves_allocated

View File

@@ -72,6 +72,7 @@
"search_index": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -336,7 +337,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-27 06:38:10.006224",
"modified": "2014-09-09 05:35:33.807228",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip",

View File

@@ -45,7 +45,7 @@ class SalarySlip(TransactionBase):
def get_leave_details(self, lwp=None):
if not self.fiscal_year:
self.fiscal_year = frappe.get_default("fiscal_year")
self.fiscal_year = frappe.db.get_default("fiscal_year")
if not self.month:
self.month = "%02d" % getdate(nowdate()).month
@@ -156,7 +156,7 @@ class SalarySlip(TransactionBase):
/ cint(self.total_days_in_month), 2)
elif not self.payment_days:
d.e_modified_amount = 0
else:
elif not d.e_modified_amount:
d.e_modified_amount = d.e_amount
self.gross_pay += flt(d.e_modified_amount)
@@ -168,7 +168,7 @@ class SalarySlip(TransactionBase):
/ cint(self.total_days_in_month), 2)
elif not self.payment_days:
d.d_modified_amount = 0
else:
elif not d.d_modified_amount:
d.d_modified_amount = d.d_amount
self.total_deduction += flt(d.d_modified_amount)
@@ -191,9 +191,6 @@ class SalarySlip(TransactionBase):
if receiver:
subj = 'Salary Slip - ' + cstr(self.month) +'/'+cstr(self.fiscal_year)
sendmail([receiver], subject=subj, msg = _("Please see attachment"),
attachments=[{
"fname": self.name + ".pdf",
"fcontent": frappe.get_print_format(self.doctype, self.name, as_pdf = True)
}])
attachments=[frappe.attach_print(self.doctype, self.name, file_name=self.name)])
else:
msgprint(_("Company Email ID not found, hence mail not sent"))

View File

@@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
def execute(filters=None):
@@ -15,9 +16,9 @@ def execute(filters=None):
def get_columns():
return [
"Employee:Link/Employee:120", "Name:Data:200", "Date of Birth:Date:100",
"Branch:Link/Branch:120", "Department:Link/Department:120",
"Designation:Link/Designation:120", "Gender::60", "Company:Link/Company:120"
_("Employee") + ":Link/Employee:120", _("Name") + ":Data:200", _("Date of Birth")+ ":Date:100",
_("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120",
_("Designation") + ":Link/Designation:120", _("Gender") + "::60", _("Company") + ":Link/Company:120"
]
def get_employees(filters):

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