Compare commits

...

114 Commits

Author SHA1 Message Date
Nabin Hait
13bd538aca Merge branch 'develop' 2015-06-14 22:04:51 +05:30
Nabin Hait
d72a24965b bumped to version 5.0.23 2015-06-14 22:34:51 +06:00
Nabin Hait
dc633fe360 Merge pull request #3470 from nabinhait/develop
Performance upgrade in reports and indexing
2015-06-14 22:01:30 +05:30
Nabin Hait
39046d663d [patch] Add index on Account and GL Entry table 2015-06-14 20:59:28 +05:30
Nabin Hait
6b01abe9ad [report][performance] Speed increased by approx 10 times in Trial Balance, General Ledger, AR/AP, Balance Sheet and P&L Statement 2015-06-14 20:59:28 +05:30
Nabin Hait
87edd86854 Merge branch 'develop' 2015-06-12 18:06:21 +05:30
Nabin Hait
e37dd77923 bumped to version 5.0.22 2015-06-12 18:36:21 +06:00
Nabin Hait
e4f689184f Merge pull request #3459 from neilLasrado/po
Multiple Fixes.
2015-06-12 17:55:23 +05:30
Nabin Hait
85f825e98c Merge pull request #3463 from nabinhait/develop
multiple issues
2015-06-12 17:48:54 +05:30
Nabin Hait
89592c5180 Load tasks in project for printing purpose 2015-06-12 17:37:28 +05:30
Neil Trini Lasrado
587bd144d5 Added Customers Not Buying Since Long Time against Sales Invoice 2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
1f048b2426 Fixes in Activity Cost 2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
1792ff3be7 Validation added in Purchase Invoice to check if Supplier Invoice Date is greater than Posting Date
Check Supplier Invoice Number Uniqueness setting added to Accounts Settings
Validation added in Purchase Invoice to check Supplier Invoice Number Uniqueness if Check Supplier Invoice Number Uniqueness is enabled in Accounts Settings
2015-06-11 18:36:52 +05:30
Neil Trini Lasrado
fc595064e0 validation added to prevent Delivery Date in Porduction Order to be lesser than Planned Start Date 2015-06-11 18:36:52 +05:30
Nabin Hait
804b4acb9b [fix] Issue fixed in C-Form related to field renaming 2015-06-11 16:56:36 +05:30
Nabin Hait
5c7557914b Removed BOM No from mandatory from Stock Entry against Production Order 2015-06-11 16:50:35 +05:30
Nabin Hait
381a9377d9 Merge branch 'develop' 2015-06-11 16:14:48 +05:30
Nabin Hait
9bdd1aa1ed bumped to version 5.0.21 2015-06-11 16:44:48 +06:00
Nabin Hait
d0df28bfa0 Merge pull request #3458 from nabinhait/develop
[fix] load tasks in project via __setup__ instead of onload function, to return tasks via get_doc
2015-06-11 16:12:05 +05:30
Nabin Hait
1966225450 [fix] load tasks in project via __setup__ instead of onload function, to return tasks via get_doc 2015-06-11 15:31:47 +05:30
Nabin Hait
4cee27eec0 Merge pull request #3446 from anandpdoshi/anand-june-9
POS - search by Item Group
2015-06-10 18:42:14 +05:30
Nabin Hait
c7d4eaee79 Merge pull request #3442 from nabinhait/develop
fixes in stock entry and report
2015-06-10 18:40:42 +05:30
Nabin Hait
43c1a9b502 [fix] Quote url for item image in product listing page 2015-06-10 18:23:17 +05:30
Nabin Hait
b937fac3ce [report] Warehouse column added in 'Ordered Items to be Delivered' report 2015-06-10 18:21:57 +05:30
Nabin Hait
53d94996ad [fix] Query for Against Journal Entry 2015-06-10 18:20:18 +05:30
Anand Doshi
26f6752c1e POS - search by Item Group 2015-06-09 16:33:46 -04:00
Nabin Hait
bb429745c0 [fix] Blank option in naming series 2015-06-09 18:59:51 +05:30
Nabin Hait
909f0c38f1 [report][enhancement] Payment period based on invoice date: show party columns and filter based on party 2015-06-09 18:42:52 +05:30
Nabin Hait
a790ba05f4 [fix] Item name, description should not be overwritten on saving of stock entry 2015-06-09 18:42:52 +05:30
Nabin Hait
11fc4f85d0 Merge branch 'develop' 2015-06-09 15:56:20 +05:30
Nabin Hait
17452a1695 bumped to version 5.0.20 2015-06-09 16:26:20 +06:00
Nabin Hait
7c3d48e353 Merge pull request #3434 from neilLasrado/material-request
Status Indicators fixed in Material Request List
2015-06-09 15:47:46 +05:30
Neil Trini Lasrado
5d288e407c item variants patch removed 2015-06-09 15:46:57 +05:30
Neil Trini Lasrado
f64fae752f fixes 2015-06-09 15:46:57 +05:30
Neil Trini Lasrado
82763f052f Status Indicators fixed in Material Request List 2015-06-09 15:46:57 +05:30
Nabin Hait
bafc73568a Merge pull request #3435 from neilLasrado/barcode
Barcode added to Purchase Receipt
2015-06-09 15:44:09 +05:30
Neil Trini Lasrado
d015195617 fixes in barcode 2015-06-09 15:21:50 +05:30
Neil Trini Lasrado
b2f550ccb3 Barcode added to Purchase Receipt 2015-06-09 15:18:58 +05:30
Nabin Hait
41413af42d Merge pull request #3437 from anandpdoshi/task-close-assignment
[fix] Close assignment (ToDo) when Task status is changed to Closed
2015-06-09 15:00:06 +05:30
Anand Doshi
ec60ebde6f [fix] Close assignment (ToDo) when Task status is changed to Closed 2015-06-08 12:48:11 -04:00
Nabin Hait
ce81a61fe7 Merge branch 'develop' 2015-06-08 14:45:13 +05:30
Nabin Hait
dc76b3fa20 bumped to version 5.0.19 2015-06-08 15:15:13 +06:00
Nabin Hait
828cbee12a Merge pull request #3429 from neilLasrado/quality-inspection
Get Item Details in Quality Inspection.
2015-06-08 14:24:11 +05:30
Nabin Hait
5f5ef16b91 Merge pull request #3430 from nabinhait/develop
Multiple fixes
2015-06-08 14:23:52 +05:30
Nabin Hait
686ef8308a Show item name in item grid view based 'In List View' property 2015-06-08 14:22:56 +05:30
Nabin Hait
b63ad44b10 Book in round-off account upto max 0.05 2015-06-08 14:15:12 +05:30
Nabin Hait
5ef121bc10 get party details only if party exists 2015-06-08 14:15:11 +05:30
Neil Trini Lasrado
42c1836db5 function changed to add fetch 2015-06-08 13:09:11 +05:30
Neil Trini Lasrado
9dbdef3bd5 added code to fetch item name and desc on change of item code 2015-06-08 12:29:12 +05:30
Nabin Hait
9fd42ed2f7 Merge pull request #3428 from nabinhait/develop
[fix] Fiscal year issue due to missing field in Material Request
2015-06-08 12:27:27 +05:30
Nabin Hait
000835c454 [fix] Fiscal year issue due to missing field in Material Request 2015-06-08 12:10:43 +05:30
Nabin Hait
de1f934e22 Merge pull request #3422 from nabinhait/develop
Manufactured qty in Stock Entry
2015-06-08 12:07:47 +05:30
Nabin Hait
7cbd916b00 [fix] Fiscal year issue due to missing field in Material Request 2015-06-08 12:06:33 +05:30
Nabin Hait
56fcf30cb9 [Patch] Update material transferred for manufacturing for existing entries 2015-06-05 18:21:35 +05:30
Nabin Hait
ebbdd772a9 [fix] Validate and update manufactured qty in Stock Entry 2015-06-05 18:21:35 +05:30
Pratik Vyas
6268d83173 Merge branch 'develop' 2015-06-05 15:56:49 +05:30
Pratik Vyas
4599467939 bumped to version 5.0.18 2015-06-05 16:26:49 +06:00
Nabin Hait
d3613479c6 Merge pull request #3421 from nabinhait/develop
pos link and item description
2015-06-05 15:51:03 +05:30
Nabin Hait
6bf301f53c Show item description in grid view based on 'In List View' property 2015-06-05 15:49:25 +05:30
Nabin Hait
27d7f21553 [fix] pos profile link in Start POS page 2015-06-05 15:09:44 +05:30
Nabin Hait
8f87cff4bd Merge pull request #3411 from nabinhait/develop
journal entry against expense claim and bank reco
2015-06-05 14:31:23 +05:30
Nabin Hait
8f39766924 Merge pull request #3419 from neilLasrado/time-log
operation made non mandatory in time log
2015-06-05 14:30:22 +05:30
Neil Trini Lasrado
39669f2717 operation made non mandatory in time log 2015-06-05 12:17:46 +05:30
Nabin Hait
3c1017c43b Removed deprecated page users 2015-06-05 12:15:01 +05:30
Nabin Hait
0b18a2d347 Reset values in tools like Payment Tool 2015-06-05 12:01:29 +05:30
Nabin Hait
6262496e70 [fix] item test case 2015-06-03 18:33:47 +05:30
Nabin Hait
c9963f1805 [fix] journal entry against expense claim: pending amount validation 2015-06-03 18:01:09 +05:30
Nabin Hait
8a2b1bcb97 [fix] bank reconciliation: fetch journal entry order by posting date asc 2015-06-03 18:01:09 +05:30
Pratik Vyas
b8ecf7c757 Merge branch 'develop' 2015-06-03 17:43:38 +05:30
Pratik Vyas
cf89fa2253 bumped to version 5.0.17 2015-06-03 18:13:38 +06:00
Nabin Hait
419c1eb90d Merge pull request #3410 from nabinhait/develop
[fix][patch] force reload web-form-field in portal fixes patch
2015-06-03 17:43:01 +05:30
Nabin Hait
2c214e0362 [fix][patch] force reload web-form-field in portal fixes patch 2015-06-03 17:42:12 +05:30
Nabin Hait
7d04dd0bfd Merge pull request #3408 from williamjmorenor/patch-1
Update Chart of Account for Nicaragua
2015-06-03 17:17:09 +05:30
Nabin Hait
f1371a7ee7 Merge pull request #3409 from nabinhait/develop
Multiple fixes
2015-06-03 17:15:42 +05:30
Nabin Hait
995a78421a [fix] Stock analytics report fixed for fifo stack related to stock reco 2015-06-03 16:44:26 +05:30
Nabin Hait
352187bee6 purchase register fix 2015-06-03 12:06:19 +05:30
Nabin Hait
c6d8121f4a delete fields inline description 2015-06-03 11:24:37 +05:30
Nabin Hait
030ade428b dont reset company on deleting company transactions 2015-06-03 11:24:37 +05:30
Nabin Hait
c87595b2da show item description in item grid view if marked for 'In List View' 2015-06-03 11:24:37 +05:30
Nabin Hait
42f2674cba dynamic link in quotation item 2015-06-03 11:24:37 +05:30
Nabin Hait
5359f2651a [fix] sales register report 2015-06-03 11:24:37 +05:30
William Moreno
42dcffdad4 Update Chart of Account for Nicaragua
Hi

The Law 891 reform some taxes rates, please update the Chart of Account for Nicaragua so it can reflect the new tax rates.
2015-06-02 16:48:47 -06:00
Anand Doshi
f7c1743b28 [hotfix] cart - get_address_docs 2015-06-02 15:20:25 -04:00
Anand Doshi
64aa6620be [hotfix] portal fixes patch 2015-06-02 11:53:17 -04:00
Rushabh Mehta
ed43f8015c [lang] let locale be en in setup wizard (?) 2015-06-02 12:31:03 +05:30
Rushabh Mehta
d3fe7ec858 [cleanup] customer not buying since long time report 2015-06-02 12:21:17 +05:30
Rushabh Mehta
c8b406d050 [fix] duplicate status for Submitted, Cancelled 2015-06-02 12:17:14 +05:30
Rushabh Mehta
2aa577f110 [hot] patch-fix 2015-06-02 11:12:25 +05:30
Pratik Vyas
f06d175061 Merge branch 'develop' 2015-06-02 10:45:28 +05:30
Pratik Vyas
74b2116adb bumped to version 5.0.16 2015-06-02 11:15:28 +06:00
Rushabh Mehta
2204d0af94 Merge pull request #3397 from rmehta/portal-fixes
Portal fixes
2015-06-02 10:42:59 +05:30
Pratik Vyas
b8a568765d Update translations 2015-06-01 23:49:15 +05:30
Rushabh Mehta
cf29f6468d [minor] add attachment to issue via portal: 2015-06-01 17:47:03 +05:30
Rushabh Mehta
aded46d33e [fix] product search in new block header_actions 2015-06-01 17:23:42 +05:30
Pratik Vyas
b8dd046c84 Merge branch 'develop' 2015-06-01 17:17:46 +05:30
Pratik Vyas
e5fa5e6111 bumped to version 5.0.15 2015-06-01 17:47:46 +06:00
Nabin Hait
b89cf1b3ec Merge pull request #3396 from nabinhait/develop
item table print template
2015-06-01 17:16:00 +05:30
Rushabh Mehta
a33d468d30 [fixes] portal, issues, addresses etc 2015-06-01 17:15:42 +05:30
Nabin Hait
e481a211b1 item table print template 2015-06-01 17:12:55 +05:30
Rushabh Mehta
ca23b5ecfd Merge pull request #3395 from nabinhait/develop
GL Entries for Journal Entries with multiple Party
2015-06-01 16:35:36 +05:30
Nabin Hait
11190268ab [fix][patch] GL Entries for Journal Entries with multiple Party, merge entries considering party 2015-06-01 16:21:25 +05:30
Nabin Hait
a19150ddaf default account's custom query in company 2015-06-01 15:32:57 +05:30
Nabin Hait
c17dff4b01 default account's custom query in company 2015-06-01 15:32:57 +05:30
Pratik Vyas
47fe136d15 Merge branch 'develop' 2015-06-01 14:51:17 +05:30
Pratik Vyas
8f25402dce bumped to version 5.0.14 2015-06-01 15:21:17 +06:00
Nabin Hait
a9165744e2 Merge pull request #3385 from nabinhait/develop
In standard print format, item name will now honour 'Print Hide' property
2015-06-01 14:03:11 +05:30
Nabin Hait
3ebfad7115 minor fixes 2015-06-01 14:01:56 +05:30
Nabin Hait
c7ef8dda79 [fix] Pricing Rule based on qty 2015-06-01 14:01:56 +05:30
Nabin Hait
4a6c178795 On selection of item, set default qty as 1 2015-06-01 14:01:56 +05:30
Nabin Hait
8908543a9c In standard print format, item name will now honour 'Print Hide' property 2015-06-01 14:01:56 +05:30
Rushabh Mehta
065badc54b [minor] move buttons from sales invoice to toolbar 2015-05-31 10:36:47 +05:30
Nabin Hait
cd2798368b Merge pull request #3384 from rmehta/journal-entry-ux
[minor] journal entry, copy over party details to new row and automatically set difference
2015-05-29 17:09:53 +05:30
Rushabh Mehta
2c30acdcb2 [minor] journal entry, copy over party details to new row and automatically set difference 2015-05-29 16:33:36 +05:30
Rushabh Mehta
4a4a6594d1 [minor] [refactor] 2015-05-29 15:56:40 +05:30
135 changed files with 2418 additions and 2325 deletions

View File

@@ -1,2 +1,2 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '5.0.13' __version__ = '5.0.23'

View File

@@ -35,7 +35,7 @@
"permlevel": 0, "permlevel": 0,
"read_only": 1, "read_only": 1,
"reqd": 1, "reqd": 1,
"search_index": 1 "search_index": 0
}, },
{ {
"default": "0", "default": "0",
@@ -44,7 +44,7 @@
"label": "Is Group", "label": "Is Group",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"search_index": 1 "search_index": 0
}, },
{ {
"fieldname": "company", "fieldname": "company",
@@ -57,7 +57,7 @@
"permlevel": 0, "permlevel": 0,
"read_only": 1, "read_only": 1,
"reqd": 1, "reqd": 1,
"search_index": 1 "search_index": 0
}, },
{ {
"fieldname": "root_type", "fieldname": "root_type",
@@ -147,7 +147,8 @@
"label": "Lft", "label": "Lft",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1,
"search_index": 1
}, },
{ {
"fieldname": "rgt", "fieldname": "rgt",
@@ -156,7 +157,8 @@
"label": "Rgt", "label": "Rgt",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1,
"search_index": 1
}, },
{ {
"fieldname": "old_parent", "fieldname": "old_parent",
@@ -171,7 +173,7 @@
"icon": "icon-money", "icon": "icon-money",
"idx": 1, "idx": 1,
"in_create": 0, "in_create": 0,
"modified": "2015-05-28 14:10:40.606010", "modified": "2015-06-14 20:57:55.471334",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Account", "name": "Account",

View File

@@ -1,6 +1,6 @@
{ {
"country_code": "ni", "country_code": "ni",
"name": "Catalogo de Cuentas", "name": "Catalogo de Cuentas Nicaragua",
"is_active": "Yes", "is_active": "Yes",
"tree": { "tree": {
"Activo": { "Activo": {
@@ -72,7 +72,7 @@
"IVA Acreditable por Importaciones": { "IVA Acreditable por Importaciones": {
"account_type": "Tax" "account_type": "Tax"
}, },
"IVA Acreditable por Prestacion de Servicios": { "IVA Acreditable por Prestacion de Servicios y Uso y Goce de Bienes": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Acreditacion Proporcional": {} "Acreditacion Proporcional": {}
@@ -229,11 +229,19 @@
"Impuesto al Valor Agregado por Pagar": { "Impuesto al Valor Agregado por Pagar": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Impuesto sobre la Renta": { "Impuesto sobre la Renta por Actividades Economicas": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Impuestos Municipales": { "Impuestos Municipales": {
"Impuesto Municipal Sobre Ingresos": {
"account_type": "Tax" "account_type": "Tax"
},
"Recoleccion Basura": {
"account_type": "Tax"
},
"Matricula Municipal": {
"account_type": "Tax"
}
} }
}, },
"Retenciones por Pagar": { "Retenciones por Pagar": {
@@ -241,7 +249,13 @@
"Retencion Rentas del Trabajo Tarifa Progresiva": { "Retencion Rentas del Trabajo Tarifa Progresiva": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Retencion Definitiva por Rentas del Trabajo": { "Retencion Definitiva 10% por Rentas del Trabajo - Indemnizacion Adicional": {
"account_type": "Tax"
},
"Retencion Definitiva 12.5% por Rentas del Trabajo - Dietas": {
"account_type": "Tax"
},
"Retencion Definitiva 15% por Rentas del Trabajo - No Residentes": {
"account_type": "Tax" "account_type": "Tax"
} }
}, },
@@ -258,11 +272,26 @@
"Retencion 5% compra Madera en Rollo": { "Retencion 5% compra Madera en Rollo": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Retencion Definitiva 1.5% Actividades Economicas No Residentes": {
"account_type": "Tax"
},
"Retencion Definitiva 3% Actividades Economicas No Residentes": {
"account_type": "Tax"
},
"Retencion Definitiva 10% Actividades Economicas No Residentes": {
"account_type": "Tax"
},
"Retencion Definitiva 15% Actividades Economicas No Residentes": {
"account_type": "Tax"
},
"Otras Retenciones 10%": { "Otras Retenciones 10%": {
"account_type": "Tax" "account_type": "Tax"
} }
}, },
"Rentas y Ganancias de Capital": { "Rentas y Ganancias de Capital": {
"Retencion Defintiva 15% por Rentas de Capital": {
"account_type": "Tax"
},
"Retencion Defintiva 10% por Rentas de Capital": { "Retencion Defintiva 10% por Rentas de Capital": {
"account_type": "Tax" "account_type": "Tax"
}, },
@@ -272,10 +301,16 @@
"Retencion Definitiva 10% por Ganancia de Capital": { "Retencion Definitiva 10% por Ganancia de Capital": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Retencion Definitiva Actividades Economicas No Residentes": { "Retencion Definitiva 0.25% Transacciones Bursatiles": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Retencion Definitiva Transacciones Bursatiles": { "Retencion Definitiva 1% Transacciones Bursatiles": {
"account_type": "Tax"
},
"Retencion Definitiva 1.5% Transacciones Bursatiles": {
"account_type": "Tax"
},
"Retencion Definitiva 2% Transacciones Bursatiles": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Retenciones Defintiva 5% Fondos de Inversion": { "Retenciones Defintiva 5% Fondos de Inversion": {

View File

@@ -4,6 +4,13 @@
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"fields": [ "fields": [
{
"fieldname": "check_supplier_invoice_uniqueness",
"fieldtype": "Check",
"label": "Check Supplier Invoice Number Uniqueness",
"permlevel": 0,
"precision": ""
},
{ {
"default": "1", "default": "1",
"description": "If enabled, the system will post accounting entries for inventory automatically.", "description": "If enabled, the system will post accounting entries for inventory automatically.",
@@ -43,7 +50,7 @@
"icon": "icon-cog", "icon": "icon-cog",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"modified": "2015-02-05 05:11:34.163902", "modified": "2015-06-11 06:06:34.047890",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@@ -2,6 +2,10 @@
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Bank Reconciliation", { frappe.ui.form.on("Bank Reconciliation", {
refresh: function(frm) {
frm.disable_save();
},
update_clearance_date: function(frm) { update_clearance_date: function(frm) {
return frappe.call({ return frappe.call({
method: "update_details", method: "update_details",
@@ -34,4 +38,3 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
cur_frm.set_value("from_date", frappe.datetime.month_start()); cur_frm.set_value("from_date", frappe.datetime.month_start());
cur_frm.set_value("to_date", frappe.datetime.month_end()); cur_frm.set_value("to_date", frappe.datetime.month_end());
} }

View File

@@ -25,7 +25,8 @@ class BankReconciliation(Document):
where where
t2.parent = t1.name and t2.account = %s t2.parent = t1.name and t2.account = %s
and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1 and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1
and ifnull(t1.is_opening, 'No') = 'No' %s""" % and ifnull(t1.is_opening, 'No') = 'No' %s
order by t1.posting_date""" %
('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1) ('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
self.set('journal_entries', []) self.set('journal_entries', [])

View File

@@ -54,7 +54,7 @@ class CForm(Document):
frappe.throw(_("Please enter atleast 1 invoice in the table")) frappe.throw(_("Please enter atleast 1 invoice in the table"))
def set_total_invoiced_amount(self): def set_total_invoiced_amount(self):
total = sum([flt(d.base_grand_total) for d in self.get('invoices')]) total = sum([flt(d.grand_total) for d in self.get('invoices')])
frappe.db.set(self, 'total_invoiced_amount', total) frappe.db.set(self, 'total_invoiced_amount', total)
def get_invoice_details(self, invoice_no): def get_invoice_details(self, invoice_no):

View File

@@ -48,7 +48,8 @@
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"label": "Party", "label": "Party",
"options": "party_type", "options": "party_type",
"permlevel": 0 "permlevel": 0,
"search_index": 1
}, },
{ {
"fieldname": "cost_center", "fieldname": "cost_center",
@@ -192,7 +193,7 @@
"icon": "icon-list", "icon": "icon-list",
"idx": 1, "idx": 1,
"in_create": 1, "in_create": 1,
"modified": "2015-04-27 20:32:48.246818", "modified": "2015-06-14 20:57:19.800276",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "GL Entry", "name": "GL Entry",

View File

@@ -4,7 +4,7 @@
frappe.provide("erpnext.accounts"); frappe.provide("erpnext.accounts");
frappe.require("assets/erpnext/js/utils.js"); frappe.require("assets/erpnext/js/utils.js");
erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
onload: function() { onload: function() {
this.load_defaults(); this.load_defaults();
this.setup_queries(); this.setup_queries();
@@ -130,10 +130,31 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
cur_frm.cscript.update_totals(me.frm.doc); cur_frm.cscript.update_totals(me.frm.doc);
} }
}); });
},
accounts_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
$.each(doc.accounts, function(i, d) {
if(d.account && d.party && d.party_type) {
row.account = d.account;
row.party = d.party;
row.party_type = d.party_type;
} }
});
// set difference
if(doc.difference) {
if(doc.difference > 0) {
row.credit = doc.difference;
} else {
row.debit = -doc.difference;
}
}
},
}); });
cur_frm.script_manager.make(erpnext.accounts.JournalVoucher); cur_frm.script_manager.make(erpnext.accounts.JournalEntry);
cur_frm.cscript.refresh = function(doc) { cur_frm.cscript.refresh = function(doc) {
erpnext.toggle_naming_series(); erpnext.toggle_naming_series();

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, cint from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _, scrub from frappe import msgprint, _, scrub
from erpnext.setup.utils import get_company_currency from erpnext.setup.utils import get_company_currency
from erpnext.controllers.accounts_controller import AccountsController from erpnext.controllers.accounts_controller import AccountsController
@@ -81,7 +81,8 @@ class JournalEntry(AccountsController):
frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx)) frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
def check_credit_limit(self): def check_credit_limit(self):
customers = list(set([d.party for d in self.get("accounts") if d.party_type=="Customer" and flt(d.debit) > 0])) customers = list(set([d.party for d in self.get("accounts")
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
if customers: if customers:
from erpnext.selling.doctype.customer.customer import check_credit_limit from erpnext.selling.doctype.customer.customer import check_credit_limit
for customer in customers: for customer in customers:
@@ -427,12 +428,11 @@ class JournalEntry(AccountsController):
def validate_expense_claim(self): def validate_expense_claim(self):
for d in self.accounts: for d in self.accounts:
if d.against_expense_claim: if d.against_expense_claim:
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim", d.against_expense_claim, sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim",
("total_sanctioned_amount", "total_amount_reimbursed")) d.against_expense_claim, ("total_sanctioned_amount", "total_amount_reimbursed"))
pending_amount = cint(sanctioned_amount) - cint(reimbursed_amount) pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
if d.debit > pending_amount: if d.debit > pending_amount:
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. \ frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
def validate_credit_debit_note(self): def validate_credit_debit_note(self):
if self.stock_entry: if self.stock_entry:
@@ -458,11 +458,11 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
if voucher_type=="Bank Entry": if voucher_type=="Bank Entry":
account = frappe.db.get_value("Company", company, "default_bank_account") account = frappe.db.get_value("Company", company, "default_bank_account")
if not account: if not account:
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank"}) account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
elif voucher_type=="Cash Entry": elif voucher_type=="Cash Entry":
account = frappe.db.get_value("Company", company, "default_cash_account") account = frappe.db.get_value("Company", company, "default_cash_account")
if not account: if not account:
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash"}) account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
if account: if account:
return { return {
@@ -538,15 +538,13 @@ def get_opening_accounts(company):
def get_against_jv(doctype, txt, searchfield, start, page_len, filters): def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("party"):
return []
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = '' and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = ''
and ifnull(jv_detail.against_jv, '') = '' ) and ifnull(jv_detail.against_jv, '') = '' )
and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield), and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield),
(filters["account"], filters["party"], "%{0}%".format(txt), start, page_len)) (filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
@frappe.whitelist() @frappe.whitelist()
def get_outstanding(args): def get_outstanding(args):

View File

@@ -45,6 +45,10 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}); });
}, },
refresh: function() {
this.frm.disable_save();
},
party: function() { party: function() {
var me = this var me = this
if(!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) { if(!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {

View File

@@ -32,6 +32,7 @@ frappe.ui.form.on("Payment Tool", "onload", function(frm) {
}); });
frappe.ui.form.on("Payment Tool", "refresh", function(frm) { frappe.ui.form.on("Payment Tool", "refresh", function(frm) {
frm.disable_save();
frappe.ui.form.trigger("Payment Tool", "party_type"); frappe.ui.form.trigger("Payment Tool", "party_type");
}); });

View File

@@ -312,7 +312,7 @@
"is_submittable": 0, "is_submittable": 0,
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"modified": "2015-02-21 03:59:08.154966", "modified": "2015-06-05 11:17:33.843334",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Tool", "name": "Payment Tool",

View File

@@ -205,9 +205,9 @@ def get_pricing_rules(args):
def filter_pricing_rules(args, pricing_rules): def filter_pricing_rules(args, pricing_rules):
# filter for qty # filter for qty
if pricing_rules and args.get("qty"): if pricing_rules:
pricing_rules = filter(lambda x: (args.qty>=flt(x.min_qty) pricing_rules = filter(lambda x: (flt(args.get("qty"))>=flt(x.min_qty)
and (args.qty<=x.max_qty if x.max_qty else True)), pricing_rules) and (flt(args.get("qty"))<=x.max_qty if x.max_qty else True)), pricing_rules)
# find pricing rule with highest priority # find pricing rule with highest priority
if pricing_rules: if pricing_rules:

View File

@@ -39,6 +39,7 @@ class PurchaseInvoice(BuyingController):
self.po_required() self.po_required()
self.pr_required() self.pr_required()
self.validate_supplier_invoice()
self.check_active_purchase_items() self.check_active_purchase_items()
self.check_conversion_rate() self.check_conversion_rate()
self.validate_credit_to_acc() self.validate_credit_to_acc()
@@ -386,6 +387,16 @@ class PurchaseInvoice(BuyingController):
project.save() project.save()
project_list.append(d.project_name) project_list.append(d.project_name)
def validate_supplier_invoice(self):
if self.bill_date:
if self.bill_date > self.posting_date:
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
if self.bill_no:
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no, "fiscal_year": self.fiscal_year})
if pi:
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
@frappe.whitelist() @frappe.whitelist()
def get_expense_account(doctype, txt, searchfield, start, page_len, filters): def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond from erpnext.controllers.queries import get_match_cond

View File

@@ -40,7 +40,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text", "fieldtype": "Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Text", "oldfieldtype": "Text",
@@ -452,7 +452,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:16.341373", "modified": "2015-06-02 14:18:56.294949",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice Item", "name": "Purchase Invoice Item",

View File

@@ -7,6 +7,7 @@ import frappe
@frappe.whitelist() @frappe.whitelist()
def get_items(price_list, sales_or_purchase, item=None): def get_items(price_list, sales_or_purchase, item=None):
condition = "" condition = ""
order_by = ""
args = {"price_list": price_list} args = {"price_list": price_list}
if sales_or_purchase == "Sales": if sales_or_purchase == "Sales":
@@ -30,16 +31,25 @@ def get_items(price_list, sales_or_purchase, item=None):
item_code[0]["barcode"] = item item_code[0]["barcode"] = item
return item_code return item_code
condition += " and (CONCAT(i.name, i.item_name) like %(name)s or (i.variant_of like %(name)s))" condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))"
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999),
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
args["name"] = "%%%s%%" % item args["name"] = "%%%s%%" % item
args["_name"] = item.replace("%", "")
# locate function is used to sort by closest match from the beginning of the value
return frappe.db.sql("""select i.name, i.item_name, i.image, return frappe.db.sql("""select i.name, i.item_name, i.image,
item_det.price_list_rate, item_det.currency item_det.price_list_rate, item_det.currency
from `tabItem` i LEFT JOIN from `tabItem` i LEFT JOIN
(select item_code, price_list_rate, currency from (select item_code, price_list_rate, currency from
`tabItem Price` where price_list=%s) item_det `tabItem Price` where price_list=%(price_list)s) item_det
ON ON
(item_det.item_code=i.name or item_det.item_code=i.variant_of) (item_det.item_code=i.name or item_det.item_code=i.variant_of)
where where
ifnull(i.has_variants, 0) = 0 and ifnull(i.has_variants, 0) = 0 and
%s""" % ('%(price_list)s', condition), args, as_dict=1) {condition}
order by
{order_by}
i.name""".format(condition=condition, order_by=order_by), args, as_dict=1)

View File

@@ -65,7 +65,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}); });
if(!from_delivery_note) { if(!from_delivery_note) {
cur_frm.page.add_menu_item(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck") cur_frm.add_custom_button(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'], "icon-truck")
} }
} }
@@ -75,14 +75,14 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
} }
// Show buttons only when pos view is active // Show buttons only when pos view is active
if (doc.docstatus===0 && !cur_frm.page.current_view_name!=="pos") { if (cint(doc.docstatus==0) && cur_frm.page.current_view_name!=="pos") {
cur_frm.cscript.sales_order_btn(); cur_frm.cscript.sales_order_btn();
cur_frm.cscript.delivery_note_btn(); cur_frm.cscript.delivery_note_btn();
} }
}, },
sales_order_btn: function() { sales_order_btn: function() {
this.$sales_order_btn = cur_frm.page.add_menu_item(__('From Sales Order'), this.$sales_order_btn = cur_frm.add_custom_button(__('From Sales Order'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice", method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
@@ -99,7 +99,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}, },
delivery_note_btn: function() { delivery_note_btn: function() {
this.$delivery_note_btn = cur_frm.page.add_menu_item(__('From Delivery Note'), this.$delivery_note_btn = cur_frm.add_custom_button(__('From Delivery Note'),
function() { function() {
frappe.model.map_current_doc({ frappe.model.map_current_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice", method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",

View File

@@ -58,7 +58,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text", "fieldtype": "Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Text", "oldfieldtype": "Text",
@@ -505,7 +505,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:15.645114", "modified": "2015-06-02 14:18:45.176726",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Item", "name": "Sales Invoice Item",

View File

@@ -56,10 +56,11 @@ def merge_similar_entries(gl_map):
def check_if_in_list(gle, gl_map): def check_if_in_list(gle, gl_map):
for e in gl_map: for e in gl_map:
if e.account == gle.account and \ if e.account == gle.account \
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \ and cstr(e.get('party_type'))==cstr(gle.get('party_type')) \
and cstr(e.get('against_voucher_type')) == \ and cstr(e.get('party'))==cstr(gle.get('party')) \
cstr(gle.get('against_voucher_type')) \ and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')): and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
return e return e
@@ -101,8 +102,7 @@ def round_off_debit_credit(gl_map):
debit_credit_diff += entry.debit - entry.credit debit_credit_diff += entry.debit - entry.credit
debit_credit_diff = flt(debit_credit_diff, precision) debit_credit_diff = flt(debit_credit_diff, precision)
print debit_credit_diff, 1.0 / (10**precision) if abs(debit_credit_diff) >= (5.0 / (10**precision)):
if abs(debit_credit_diff) >= (2.0 / (10**precision)):
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.") frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff)) .format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))

View File

@@ -9,7 +9,7 @@
<button class="btn btn-primary btn-lg">{%= __("Start") %}</button> <button class="btn btn-primary btn-lg">{%= __("Start") %}</button>
</p> </p>
<p class="pos-setting-message hide"> <p class="pos-setting-message hide">
<a class="btn btn-default btn-sm" href="#Form/POS Setting/New POS Setting"> <a class="btn btn-default btn-sm" href="#Form/POS Profile/New POS Profile">
{%= __("Make new POS Setting") %}</a> {%= __("Make new POS Profile") %}</a>
</p> </p>
</div> </div>

View File

@@ -17,11 +17,15 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
if not party: if not party:
return {} return {}
if not frappe.db.exists(party_type, party):
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(party, account, party_type, return _get_party_details(party, account, party_type,
company, posting_date, price_list, currency, doctype) company, posting_date, price_list, currency, doctype)
def _get_party_details(party=None, account=None, party_type="Customer", company=None, def _get_party_details(party=None, account=None, party_type="Customer", company=None,
posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False): posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype)) out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype))
party = out[party_type.lower()] party = out[party_type.lower()]

View File

@@ -51,7 +51,7 @@ class ReceivablePayableReport(object):
currency_precision = get_currency_precision() or 2 currency_precision = get_currency_precision() or 2
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
voucher_details = self.get_voucher_details() voucher_details = self.get_voucher_details(args.get("party_type"))
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type")) future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
@@ -153,13 +153,15 @@ class ReceivablePayableReport(object):
return self.party_map return self.party_map
def get_voucher_details(self): def get_voucher_details(self, party_type):
voucher_details = frappe._dict() voucher_details = frappe._dict()
if party_type == "Customer":
for si in frappe.db.sql("""select name, due_date for si in frappe.db.sql("""select name, due_date
from `tabSales Invoice` where docstatus=1""", as_dict=1): from `tabSales Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(si.name, si) voucher_details.setdefault(si.name, si)
if party_type == "Supplier":
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
from `tabPurchase Invoice` where docstatus=1""", as_dict=1): from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
voucher_details.setdefault(pi.name, pi) voucher_details.setdefault(pi.name, pi)
@@ -169,7 +171,8 @@ class ReceivablePayableReport(object):
def get_gl_entries(self, party_type): def get_gl_entries(self, party_type):
if not hasattr(self, "gl_entries"): if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions(party_type) conditions, values = self.prepare_conditions(party_type)
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry` self.gl_entries = frappe.db.sql("""select posting_date, account, party_type, party, debit, credit,
voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
where docstatus < 2 and party_type=%s {0} order by posting_date, party""" where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
.format(conditions), values, as_dict=True) .format(conditions), values, as_dict=True)

View File

@@ -83,7 +83,7 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"], gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries) accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
calculate_values(accounts, gl_entries_by_account, period_list) calculate_values(accounts_by_name, gl_entries_by_account, period_list)
accumulate_values_into_parents(accounts, accounts_by_name, period_list) accumulate_values_into_parents(accounts, accounts_by_name, period_list)
out = prepare_data(accounts, balance_must_be, period_list) out = prepare_data(accounts, balance_must_be, period_list)
@@ -92,13 +92,11 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
return out return out
def calculate_values(accounts, gl_entries_by_account, period_list): def calculate_values(accounts_by_name, gl_entries_by_account, period_list):
for d in accounts: for entries in gl_entries_by_account.values():
for name in ([d.name] + (d.collapsed_children or [])): for entry in entries:
for entry in gl_entries_by_account.get(name, []): d = accounts_by_name.get(entry.account)
for period in period_list: for period in period_list:
entry.posting_date = getdate(entry.posting_date)
# check if posting date is within the period # check if posting date is within the period
if entry.posting_date <= period.to_date: if entry.posting_date <= period.to_date:
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit) d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
@@ -159,22 +157,8 @@ def add_total_row(out, balance_must_be, period_list):
out.append({}) out.append({})
def get_accounts(company, root_type): def get_accounts(company, root_type):
# root lft, rgt return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
root_account = frappe.db.sql("""select lft, rgt from `tabAccount` where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
where company=%s and root_type=%s and ifnull(parent_account, '') = ''
order by lft limit 1""",
(company, root_type), as_dict=True)
if not root_account:
return None
lft, rgt = root_account[0].lft, root_account[0].rgt
accounts = frappe.db.sql("""select * from `tabAccount`
where company=%(company)s and lft >= %(lft)s and rgt <= %(rgt)s order by lft""",
{ "company": company, "lft": lft, "rgt": rgt }, as_dict=True)
return accounts
def filter_accounts(accounts, depth=10): def filter_accounts(accounts, depth=10):
parent_children_map = {} parent_children_map = {}
@@ -196,14 +180,6 @@ def filter_accounts(accounts, depth=10):
filtered_accounts.append(child) filtered_accounts.append(child)
add_to_list(child.name, level + 1) add_to_list(child.name, level + 1)
else:
# include all children at level lower than the depth
parent_account = accounts_by_name[parent]
parent_account["collapsed_children"] = []
for d in accounts:
if d.lft > parent_account.lft and d.rgt < parent_account.rgt:
parent_account["collapsed_children"].append(d.name)
add_to_list(None, 0) add_to_list(None, 0)
return filtered_accounts, accounts_by_name return filtered_accounts, accounts_by_name
@@ -234,7 +210,7 @@ def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closi
if from_date: if from_date:
additional_conditions.append("and posting_date >= %(from_date)s") additional_conditions.append("and posting_date >= %(from_date)s")
gl_entries = frappe.db.sql("""select * from `tabGL Entry` gl_entries = frappe.db.sql("""select posting_date, account, debit, credit from `tabGL Entry`
where company=%(company)s where company=%(company)s
{additional_conditions} {additional_conditions}
and posting_date <= %(to_date)s and posting_date <= %(to_date)s

View File

@@ -66,7 +66,7 @@ def get_gl_entries(filters):
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party, gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit, sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
voucher_type, voucher_no, cost_center, remarks, is_opening, against voucher_type, voucher_no, cost_center, remarks, against
from `tabGL Entry` from `tabGL Entry`
where company=%(company)s {conditions} where company=%(company)s {conditions}
{group_by_condition} {group_by_condition}
@@ -92,6 +92,9 @@ def get_conditions(filters):
if filters.get("party"): if filters.get("party"):
conditions.append("party=%(party)s") conditions.append("party=%(party)s")
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
conditions.append("posting_date >=%(from_date)s")
from frappe.desk.reportview import build_match_conditions from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry") match_conditions = build_match_conditions("GL Entry")
if match_conditions: conditions.append(match_conditions) if match_conditions: conditions.append(match_conditions)
@@ -148,14 +151,15 @@ def initialize_gle_map(gl_entries):
def get_accountwise_gle(filters, gl_entries, gle_map): def get_accountwise_gle(filters, gl_entries, gle_map):
opening, total_debit, total_credit = 0, 0, 0 opening, total_debit, total_credit = 0, 0, 0
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
for gle in gl_entries: for gle in gl_entries:
amount = flt(gle.debit, 3) - flt(gle.credit, 3) amount = flt(gle.debit, 3) - flt(gle.credit, 3)
if gle.posting_date < getdate(filters.from_date): if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
and gle.posting_date < from_date:
gle_map[gle.account].opening += amount gle_map[gle.account].opening += amount
if filters.get("account") or filters.get("party"): if filters.get("account") or filters.get("party"):
opening += amount opening += amount
elif gle.posting_date <= getdate(filters.to_date): elif gle.posting_date <= to_date:
gle_map[gle.account].entries.append(gle) gle_map[gle.account].entries.append(gle)
gle_map[gle.account].total_debit += flt(gle.debit, 3) gle_map[gle.account].total_debit += flt(gle.debit, 3)
gle_map[gle.account].total_credit += flt(gle.credit, 3) gle_map[gle.account].total_credit += flt(gle.credit, 3)

View File

@@ -14,7 +14,7 @@ def execute(filters=None):
source = gross_profit_data.grouped_data if filters.get("group_by") != "Invoice" else gross_profit_data.data source = gross_profit_data.grouped_data if filters.get("group_by") != "Invoice" else gross_profit_data.data
group_wise_columns = frappe._dict({ group_wise_columns = frappe._dict({
"invoice": ["parent", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \ "invoice": ["parent", "customer", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \
"warehouse", "qty", "base_rate", "buying_rate", "base_amount", "warehouse", "qty", "base_rate", "buying_rate", "base_amount",
"buying_amount", "gross_profit", "gross_profit_percent", "project"], "buying_amount", "gross_profit", "gross_profit_percent", "project"],
"item_code": ["item_code", "item_name", "brand", "description", "warehouse", "qty", "base_rate", "item_code": ["item_code", "item_name", "brand", "description", "warehouse", "qty", "base_rate",
@@ -183,8 +183,6 @@ class GrossProfitGenerator(object):
my_sle = self.sle.get((item_code, row.warehouse)) my_sle = self.sle.get((item_code, row.warehouse))
for i, sle in enumerate(my_sle): for i, sle in enumerate(my_sle):
# find the stock valution rate from stock ledger entry # find the stock valution rate from stock ledger entry
print sle.voucher_type, row.parenttype, sle.voucher_no, row.parent, \
sle.voucher_detail_no, row.item_row
if sle.voucher_type == row.parenttype and row.parent == sle.voucher_no and \ if sle.voucher_type == row.parenttype and row.parent == sle.voucher_no and \
sle.voucher_detail_no == row.item_row: sle.voucher_detail_no == row.item_row:
previous_stock_value = len(my_sle) > i+1 and \ previous_stock_value = len(my_sle) > i+1 and \

View File

@@ -3,6 +3,14 @@
frappe.query_reports["Payment Period Based On Invoice Date"] = { frappe.query_reports["Payment Period Based On Invoice Date"] = {
"filters": [ "filters": [
{
fieldname:"company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
reqd: 1,
default: frappe.defaults.get_user_default("company")
},
{ {
fieldname: "from_date", fieldname: "from_date",
label: __("From Date"), label: __("From Date"),
@@ -23,27 +31,28 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
default: "Incoming" default: "Incoming"
}, },
{ {
fieldname:"account", "fieldname":"party_type",
label: __("Account"), "label": __("Party Type"),
fieldtype: "Link", "fieldtype": "Link",
options: "Account", "options": "DocType",
get_query: function() { "get_query": function() {
return { return {
query: "erpnext.controllers.queries.get_account_list", filters: {"name": ["in", ["Customer", "Supplier"]]}
filters: {
"report_type": "Balance Sheet",
company: frappe.query_report.filters_by_name.company.get_value()
}
} }
} }
}, },
{ {
fieldname:"company", "fieldname":"party",
label: __("Company"), "label": __("Party"),
fieldtype: "Link", "fieldtype": "Dynamic Link",
options: "Company", "get_options": function() {
reqd: 1, var party_type = frappe.query_report.filters_by_name.party_type.get_value();
default: frappe.defaults.get_user_default("company") var party = frappe.query_report.filters_by_name.party.get_value();
if(party && !party_type) {
frappe.throw(__("Please select Party Type first"));
}
return party_type;
}
}, },
] ]
} }

View File

@@ -20,16 +20,16 @@ def execute(filters=None):
for d in entries: for d in entries:
if d.against_voucher: if d.against_voucher:
against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or "" against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or ""
outstanding_amount = flt(d.debit) or -1 * flt(d.credit) payment_amount = flt(d.debit) or -1 * flt(d.credit)
else: else:
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or "" against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
outstanding_amount = flt(d.credit) or -1 * flt(d.debit) payment_amount = flt(d.credit) or -1 * flt(d.debit)
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice, row = [d.name, d.party_type, d.party, d.posting_date, d.against_voucher or d.against_invoice,
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark] against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
if d.against_voucher or d.against_invoice: if d.against_voucher or d.against_invoice:
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, outstanding_amount) row += get_ageing_data(30, 60, 90, d.posting_date, against_date, payment_amount)
else: else:
row += ["", "", "", "", ""] row += ["", "", "", "", ""]
@@ -38,7 +38,8 @@ def execute(filters=None):
return columns, data return columns, data
def get_columns(): def get_columns():
return [_("Journal Entry") + ":Link/Journal Entry:140", _("Account") + ":Link/Account:140", return [_("Journal Entry") + ":Link/Journal Entry:140",
_("Party Type") + ":Link/DocType:100", _("Party") + ":Dynamic Link/party_type:140",
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130", _("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120", _("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40", _("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
@@ -46,41 +47,38 @@ def get_columns():
] ]
def get_conditions(filters): def get_conditions(filters):
conditions = "" conditions = []
party = None
if filters.get("account"): if not filters.get("party_type"):
party = filters["account"] if filters.get("payment_type") == "Outgoing":
filters["party_type"] = "Supplier"
else: else:
conditions += " and company = '%s'" % frappe.db.escape(filters["company"]) filters["party_type"] = "Customer"
account_type = "Receivable" if filters.get("payment_type") == "Incoming" else "Payable" if filters.get("party_type"):
conditions.append("jvd.party_type=%(party_type)s")
conditions += """ and account in if filters.get("party"):
(select name from tabAccount conditions.append("jvd.party=%(party)s")
where account_type = '{0}'
and company='{1}')""".format(account_type, frappe.db.escape(filters["company"]))
if party: if filters.get("company"):
conditions += " and jvd.party = '%s'" % frappe.db.escape(party) conditions.append("jv.company=%(company)s")
else:
conditions += " and ifnull(jvd.party, '') != ''"
if filters.get("from_date"): if filters.get("from_date"):
conditions += " and jv.posting_date >= '%s'" % filters["from_date"] conditions.append("jv.posting_date >= %(from_date)s")
if filters.get("to_date"): if filters.get("to_date"):
conditions += " and jv.posting_date <= '%s'" % filters["to_date"] conditions.append("jv.posting_date <= %(to_date)s")
return conditions return "and {}".format(" and ".join(conditions)) if conditions else ""
def get_entries(filters): def get_entries(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date, entries = frappe.db.sql("""select jv.name, jvd.party_type, jvd.party, jv.posting_date,
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit, jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
jv.cheque_no, jv.cheque_date, jv.remark jv.cheque_no, jv.cheque_date, jv.remark
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" % where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
conditions, as_dict=1, debug=1) conditions, filters, as_dict=1)
return entries return entries

View File

@@ -12,7 +12,6 @@ def execute(filters=None):
invoice_list = get_invoices(filters) invoice_list = get_invoices(filters)
columns, expense_accounts, tax_accounts = get_columns(invoice_list) columns, expense_accounts, tax_accounts = get_columns(invoice_list)
if not invoice_list: if not invoice_list:
msgprint(_("No record found")) msgprint(_("No record found"))
return columns, invoice_list return columns, invoice_list
@@ -30,7 +29,8 @@ def execute(filters=None):
purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", []))) purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])))
project_name = list(set(invoice_po_pr_map.get(inv.name, {}).get("project_name", []))) project_name = list(set(invoice_po_pr_map.get(inv.name, {}).get("project_name", [])))
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name, supplier_details.get(inv.supplier), row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name,
supplier_details.get(inv.supplier),
inv.credit_to, ", ".join(project_name), inv.bill_no, inv.bill_date, inv.remarks, inv.credit_to, ", ".join(project_name), inv.bill_no, inv.bill_date, inv.remarks,
", ".join(purchase_order), ", ".join(purchase_receipt)] ", ".join(purchase_order), ", ".join(purchase_receipt)]
@@ -55,7 +55,6 @@ def execute(filters=None):
# total tax, grand total, outstanding amount & rounded total # total tax, grand total, outstanding amount & rounded total
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount] row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount]
data.append(row) data.append(row)
# raise Exception
return columns, data return columns, data
@@ -107,7 +106,7 @@ def get_conditions(filters):
def get_invoices(filters): def get_invoices(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name,
bill_no, bill_date, remarks, base_net_total, base_grand_total, outstanding_amount bill_no, bill_date, remarks, base_net_total, base_grand_total, outstanding_amount
from `tabPurchase Invoice` where docstatus = 1 %s from `tabPurchase Invoice` where docstatus = 1 %s
order by posting_date desc, name desc""" % conditions, filters, as_dict=1) order by posting_date desc, name desc""" % conditions, filters, as_dict=1)

View File

@@ -30,7 +30,8 @@ def execute(filters=None):
delivery_note = list(set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", []))) delivery_note = list(set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", [])))
row = [inv.name, inv.posting_date, inv.customer, inv.customer_name, row = [inv.name, inv.posting_date, inv.customer, inv.customer_name,
customer_map.get(inv.customer)["customer_group"], customer_map.get(inv.customer)["territory"], customer_map.get(inv.customer, {}).get("customer_group"),
customer_map.get(inv.customer, {}).get("territory"),
inv.debit_to, inv.project_name, inv.remarks, ", ".join(sales_order), ", ".join(delivery_note)] inv.debit_to, inv.project_name, inv.remarks, ", ".join(sales_order), ", ".join(delivery_note)]
# map income values # map income values

View File

@@ -9,7 +9,7 @@ from erpnext.accounts.report.financial_statements import filter_accounts, get_gl
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit") value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
def execute(filters): def execute(filters=None):
validate_filters(filters) validate_filters(filters)
data = get_data(filters) data = get_data(filters)
columns = get_columns() columns = get_columns()
@@ -45,8 +45,8 @@ def validate_filters(filters):
filters.to_date = filters.year_end_date filters.to_date = filters.year_end_date
def get_data(filters): def get_data(filters):
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""", accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
filters.company, as_dict=True) from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
if not accounts: if not accounts:
return None return None
@@ -56,17 +56,58 @@ def get_data(filters):
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount` min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
where company=%s""", (filters.company,))[0] where company=%s""", (filters.company,))[0]
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt, gl_entries_by_account = get_gl_entries(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt,
ignore_closing_entries=not flt(filters.with_period_closing_entry)) ignore_closing_entries=not flt(filters.with_period_closing_entry))
total_row = calculate_values(accounts, gl_entries_by_account, filters) opening_balances = get_opening_balances(filters)
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
accumulate_values_into_parents(accounts, accounts_by_name) accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row) data = prepare_data(accounts, filters, total_row)
return data return data
def calculate_values(accounts, gl_entries_by_account, filters): def get_opening_balances(filters):
balance_sheet_opening = get_rootwise_opening_balances(filters, "Balance Sheet")
pl_opening = get_rootwise_opening_balances(filters, "Profit and Loss")
balance_sheet_opening.update(pl_opening)
return balance_sheet_opening
def get_rootwise_opening_balances(filters, report_type):
additional_conditions = " and posting_date >= %(year_start_date)s" \
if report_type == "Profit and Loss" else ""
if not flt(filters.with_period_closing_entry):
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
gle = frappe.db.sql("""
select
account, sum(ifnull(debit, 0)) as opening_debit, sum(ifnull(credit, 0)) as opening_credit
from `tabGL Entry`
where
company=%(company)s
{additional_conditions}
and posting_date < %(from_date)s
and account in (select name from `tabAccount` where report_type=%(report_type)s)
group by account""".format(additional_conditions=additional_conditions),
{
"company": filters.company,
"from_date": filters.from_date,
"report_type": report_type,
"year_start_date": filters.year_start_date
},
as_dict=True)
opening = frappe._dict()
for d in gle:
opening.setdefault(d.account, d)
return opening
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
init = { init = {
"opening_debit": 0.0, "opening_debit": 0.0,
"opening_credit": 0.0, "opening_credit": 0.0,
@@ -88,30 +129,16 @@ def calculate_values(accounts, gl_entries_by_account, filters):
d.update(init.copy()) d.update(init.copy())
for entry in gl_entries_by_account.get(d.name, []): for entry in gl_entries_by_account.get(d.name, []):
posting_date = getdate(entry.posting_date)
# opening
if posting_date < filters.from_date:
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
(filters.year_start_date <= posting_date < filters.from_date))
if is_valid_opening:
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
elif posting_date <= filters.to_date:
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
else:
d["debit"] += flt(entry.debit) d["debit"] += flt(entry.debit)
d["credit"] += flt(entry.credit) d["credit"] += flt(entry.credit)
total_row["debit"] += d["debit"] total_row["debit"] += d["debit"]
total_row["credit"] += d["credit"] total_row["credit"] += d["credit"]
# add opening
d["opening_debit"] = opening_balances.get(d.name, {}).get("opening_debit", 0)
d["opening_credit"] = opening_balances.get(d.name, {}).get("opening_credit", 0)
return total_row return total_row
def accumulate_values_into_parents(accounts, accounts_by_name): def accumulate_values_into_parents(accounts, accounts_by_name):

View File

@@ -91,7 +91,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
# different filter for group and ledger - improved performance # different filter for group and ledger - improved performance
if acc.is_group: if acc.is_group:
cond.append("""exists ( cond.append("""exists (
select * from `tabAccount` ac where ac.name = gle.account select name from `tabAccount` ac where ac.name = gle.account
and ac.lft >= %s and ac.rgt <= %s and ac.lft >= %s and ac.rgt <= %s
)""" % (acc.lft, acc.rgt)) )""" % (acc.lft, acc.rgt))
else: else:
@@ -397,7 +397,7 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
for d in outstanding_voucher_list: for d in outstanding_voucher_list:
payment_amount = frappe.db.sql(""" payment_amount = frappe.db.sql("""
select ifnull(sum(ifnull({amount_query}, 0)), 0) select ifnull(sum({amount_query}), 0)
from from
`tabGL Entry` `tabGL Entry`
where where

View File

@@ -26,7 +26,7 @@
"reqd": 1 "reqd": 1
}, },
{ {
"description": "Supplier (vendor) name as entered in supplier master", "description": "",
"fieldname": "supplier", "fieldname": "supplier",
"fieldtype": "Link", "fieldtype": "Link",
"in_filter": 1, "in_filter": 1,
@@ -873,7 +873,7 @@
"icon": "icon-file-text", "icon": "icon-file-text",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2015-05-27 02:48:02.452899", "modified": "2015-06-02 17:15:44.711032",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@@ -75,7 +75,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
@@ -538,7 +538,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:16.553472", "modified": "2015-06-02 14:19:21.459032",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order Item", "name": "Purchase Order Item",

View File

@@ -57,3 +57,7 @@ cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
return { filters: filter } return { filters: filter }
} }
cur_frm.add_fetch('item_code', 'item_name', 'item_name');
cur_frm.add_fetch('item_code', 'description', 'description');

View File

@@ -127,6 +127,14 @@
"permlevel": 0, "permlevel": 0,
"width": "50%" "width": "50%"
}, },
{
"fieldname": "item_name",
"fieldtype": "Data",
"label": "Item Name",
"permlevel": 0,
"precision": "",
"read_only": 1
},
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
@@ -219,7 +227,7 @@
"icon": "icon-search", "icon": "icon-search",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2015-04-14 07:37:07.331291", "modified": "2015-06-08 02:40:25.121948",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Quality Inspection", "name": "Quality Inspection",

View File

@@ -31,7 +31,6 @@ class QualityInspection(Document):
(self.name, self.modified, self.purchase_receipt_no, (self.name, self.modified, self.purchase_receipt_no,
self.item_code)) self.item_code))
def on_cancel(self): def on_cancel(self):
if self.purchase_receipt_no: if self.purchase_receipt_no:
frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2 frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2
@@ -39,7 +38,6 @@ class QualityInspection(Document):
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""", where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""",
(self.modified, self.purchase_receipt_no, self.item_code)) (self.modified, self.purchase_receipt_no, self.item_code))
def item_query(doctype, txt, searchfield, start, page_len, filters): def item_query(doctype, txt, searchfield, start, page_len, filters):
if filters.get("from"): if filters.get("from"):
from frappe.desk.reportview import get_match_cond from frappe.desk.reportview import get_match_cond

View File

@@ -26,7 +26,7 @@
"reqd": 1 "reqd": 1
}, },
{ {
"description": "Supplier (vendor) name as entered in supplier master", "description": "",
"fieldname": "supplier", "fieldname": "supplier",
"fieldtype": "Link", "fieldtype": "Link",
"in_filter": 1, "in_filter": 1,
@@ -660,7 +660,7 @@
"icon": "icon-shopping-cart", "icon": "icon-shopping-cart",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2015-05-27 02:48:02.098540", "modified": "2015-06-02 17:15:57.283516",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation", "name": "Supplier Quotation",

View File

@@ -59,7 +59,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
@@ -413,7 +413,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:15.853886", "modified": "2015-06-02 14:19:33.922968",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation Item", "name": "Supplier Quotation Item",

View File

@@ -31,7 +31,7 @@ def get_data():
{ {
"type": "help", "type": "help",
"label": _("Opening Stock Balance"), "label": _("Opening Stock Balance"),
"youtube_id": "yPgrtfeCTs" "youtube_id": "0yPgrtfeCTs"
}, },
{ {
"type": "help", "type": "help",
@@ -106,7 +106,7 @@ def get_data():
{ {
"type": "help", "type": "help",
"label": _("Opening Stock Balance"), "label": _("Opening Stock Balance"),
"youtube_id": "yPgrtfeCTs" "youtube_id": "0yPgrtfeCTs"
}, },
{ {
"type": "help", "type": "help",

View File

@@ -266,7 +266,7 @@ def get_data():
{ {
"type": "help", "type": "help",
"label": _("Opening Stock Balance"), "label": _("Opening Stock Balance"),
"youtube_id": "yPgrtfeCTs" "youtube_id": "0yPgrtfeCTs"
}, },
{ {
"type": "help", "type": "help",

View File

@@ -38,6 +38,7 @@ class AccountsController(TransactionBase):
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date")) convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
def before_recurring(self): def before_recurring(self):
if self.meta.get_field("fiscal_year"):
self.fiscal_year = None self.fiscal_year = None
if self.meta.get_field("due_date"): if self.meta.get_field("due_date"):
self.due_date = None self.due_date = None
@@ -46,7 +47,7 @@ class AccountsController(TransactionBase):
for fieldname in ["posting_date", "transaction_date"]: for fieldname in ["posting_date", "transaction_date"]:
if not self.get(fieldname) and self.meta.get_field(fieldname): if not self.get(fieldname) and self.meta.get_field(fieldname):
self.set(fieldname, today()) self.set(fieldname, today())
if not self.fiscal_year: if self.meta.get_field("fiscal_year") and not self.fiscal_year:
self.fiscal_year = get_fiscal_year(self.get(fieldname))[0] self.fiscal_year = get_fiscal_year(self.get(fieldname))[0]
break break

View File

@@ -78,7 +78,7 @@ class StatusUpdater(Document):
self.status = s[0] self.status = s[0]
break break
if self.status != _status: if self.status != _status and self.status not in ("Submitted", "Cancelled"):
self.add_comment("Label", _(self.status)) self.add_comment("Label", _(self.status))
if update: if update:

View File

@@ -44,11 +44,14 @@ class NewsletterList(Document):
return self.update_total_subscribers() return self.update_total_subscribers()
def update_total_subscribers(self): def update_total_subscribers(self):
self.total_subscribers = frappe.db.sql("""select count(*) from `tabNewsletter List Subscriber` self.total_subscribers = self.get_total_subscribers()
where newsletter_list=%s""", self.name)[0][0]
self.db_update() self.db_update()
return self.total_subscribers return self.total_subscribers
def get_total_subscribers(self):
return frappe.db.sql("""select count(*) from `tabNewsletter List Subscriber`
where newsletter_list=%s""", self.name)[0][0]
def on_trash(self): def on_trash(self):
for d in frappe.get_all("Newsletter List Subscriber", "name", {"newsletter_list": self.name}): for d in frappe.get_all("Newsletter List Subscriber", "name", {"newsletter_list": self.name}):
frappe.delete_doc("Newsletter List Subscriber", d.name) frappe.delete_doc("Newsletter List Subscriber", d.name)

View File

@@ -85,7 +85,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text", "fieldtype": "Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Text", "oldfieldtype": "Text",
@@ -134,7 +134,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-14 14:55:18.325286", "modified": "2015-06-02 14:18:16.622288",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity Item", "name": "Opportunity Item",

View File

@@ -5,7 +5,7 @@ app_publisher = "Frappe Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations" app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th" app_icon = "icon-th"
app_color = "#e74c3c" app_color = "#e74c3c"
app_version = "5.0.13" app_version = "5.0.23"
error_report_email = "support@erpnext.com" error_report_email = "support@erpnext.com"
@@ -38,16 +38,14 @@ website_route_rules = [
{"from_route": "/invoices", "to_route": "Sales Invoice"}, {"from_route": "/invoices", "to_route": "Sales Invoice"},
{"from_route": "/invoices/<path:name>", "to_route": "print", "defaults": {"doctype": "Sales Invoice"}}, {"from_route": "/invoices/<path:name>", "to_route": "print", "defaults": {"doctype": "Sales Invoice"}},
{"from_route": "/shipments", "to_route": "Delivery Note"}, {"from_route": "/shipments", "to_route": "Delivery Note"},
{"from_route": "/shipments/<path:name>", "to_route": "print", "defaults": {"doctype": "Delivery Note"}}, {"from_route": "/shipments/<path:name>", "to_route": "print", "defaults": {"doctype": "Delivery Note"}}
{"from_route": "/issues", "to_route": "Issue"},
{"from_route": "/issues/<path:name>", "to_route": "print", "defaults": {"doctype": "Issue"}},
{"from_route": "/addresses", "to_route": "Address"},
] ]
has_website_permission = { has_website_permission = {
"Sales Order": "erpnext.controllers.website_list_for_contact.has_website_permission", "Sales Order": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission", "Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission" "Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Issue": "erpnext.support.doctype.issue.issue.has_website_permission"
} }
dump_report_map = "erpnext.startup.report_data_map.data_map" dump_report_map = "erpnext.startup.report_data_map.data_map"

View File

@@ -23,9 +23,6 @@ class LeaveAllocation(Document):
def on_update(self): def on_update(self):
self.get_total_allocated_leaves() self.get_total_allocated_leaves()
def on_cancel(self):
self.check_for_leave_application()
def validate_new_leaves_allocated_value(self): def validate_new_leaves_allocated_value(self):
"""validate that leave allocation is in multiples of 0.5""" """validate that leave allocation is in multiples of 0.5"""
if flt(self.new_leaves_allocated) % 0.5: if flt(self.new_leaves_allocated) % 0.5:

View File

@@ -25,3 +25,7 @@ cur_frm.cscript.allocation_type = function (doc, cdt, cdn){
doc.no_of_days = ''; doc.no_of_days = '';
refresh_field('no_of_days'); refresh_field('no_of_days');
} }
frappe.ui.form.on("Leave Control Panel", "refresh", function(frm) {
frm.disable_save();
});

View File

@@ -94,11 +94,11 @@
} }
], ],
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 1,
"icon": "icon-cog", "icon": "icon-cog",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"modified": "2015-02-05 05:11:40.791976", "modified": "2015-06-05 11:38:19.994852",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Leave Control Panel", "name": "Leave Control Panel",
@@ -110,7 +110,7 @@
"read": 1, "read": 1,
"report": 0, "report": 0,
"role": "HR User", "role": "HR User",
"share": 1, "share": 0,
"submit": 0, "submit": 0,
"write": 1 "write": 1
} }

View File

@@ -43,3 +43,8 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) {
frappe.set_route("Form", doc.doctype, doc.name); frappe.set_route("Form", doc.doctype, doc.name);
}); });
} }
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
frm.disable_save();
});

View File

@@ -150,10 +150,11 @@
"permlevel": 0 "permlevel": 0
} }
], ],
"hide_toolbar": 1,
"icon": "icon-cog", "icon": "icon-cog",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"modified": "2015-02-25 07:21:04.778082", "modified": "2015-06-05 11:33:00.152362",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Salary Manager", "name": "Salary Manager",

View File

@@ -12,6 +12,7 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
}, },
refresh: function() { refresh: function() {
this.frm.disable_save();
this.show_upload(); this.show_upload();
}, },

View File

@@ -1,4 +1,5 @@
{ {
"allow_copy": 1,
"creation": "2013-01-25 11:34:53", "creation": "2013-01-25 11:34:53",
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
@@ -53,11 +54,13 @@
"permlevel": 0 "permlevel": 0
} }
], ],
"hide_heading": 0,
"hide_toolbar": 1,
"icon": "icon-upload-alt", "icon": "icon-upload-alt",
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"max_attachments": 1, "max_attachments": 1,
"modified": "2015-02-05 05:11:48.540845", "modified": "2015-06-05 11:37:04.348120",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Upload Attendance", "name": "Upload Attendance",
@@ -65,25 +68,25 @@
"permissions": [ "permissions": [
{ {
"create": 1, "create": 1,
"email": 1, "email": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 0,
"read": 1, "read": 1,
"report": 0, "report": 0,
"role": "HR User", "role": "HR User",
"share": 1, "share": 0,
"submit": 0, "submit": 0,
"write": 1 "write": 1
}, },
{ {
"create": 1, "create": 1,
"email": 1, "email": 0,
"permlevel": 0, "permlevel": 0,
"print": 1, "print": 0,
"read": 1, "read": 1,
"report": 0, "report": 0,
"role": "HR Manager", "role": "HR Manager",
"share": 1, "share": 0,
"submit": 0, "submit": 0,
"write": 1 "write": 1
} }

View File

@@ -425,5 +425,5 @@ def validate_bom_no(item, bom_no):
if not getattr(frappe.flags, "in_test", False): if not getattr(frappe.flags, "in_test", False):
frappe.throw(_("BOM {0} must be submitted").format(bom_no)) frappe.throw(_("BOM {0} must be submitted").format(bom_no))
if item and not (bom.item.lower() == item.lower() or \ if item and not (bom.item.lower() == item.lower() or \
bom.item.lower() == frappe.db.get_value("Item", item, "variant_of").lower()): bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower()):
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item)) frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))

View File

@@ -309,10 +309,9 @@ class ProductionOrder(Document):
self.actual_end_date = None self.actual_end_date = None
def validate_delivery_date(self): def validate_delivery_date(self):
if self.docstatus==1: if self.planned_start_date and self.expected_delivery_date \
if self.planned_end_date and self.expected_delivery_date \ and getdate(self.expected_delivery_date) < getdate(self.planned_start_date):
and getdate(self.expected_delivery_date) < getdate(self.planned_end_date): frappe.throw(_("Expected Delivery Date must be greater than Planned Start Date."))
frappe.msgprint(_("Production might not be able to finish by the Expected Delivery Date."))
def delete_time_logs(self): def delete_time_logs(self):
for time_log in frappe.get_all("Time Log", ["name"], {"production_order": self.name}): for time_log in frappe.get_all("Time Log", ["name"], {"production_order": self.name}):

View File

@@ -1,4 +1,5 @@
{ {
"allow_copy": 1,
"creation": "2013-01-21 12:03:47", "creation": "2013-01-21 12:03:47",
"default_print_format": "Standard", "default_print_format": "Standard",
"docstatus": 0, "docstatus": 0,
@@ -154,11 +155,12 @@
"permlevel": 0 "permlevel": 0
} }
], ],
"hide_toolbar": 1,
"icon": "icon-calendar", "icon": "icon-calendar",
"idx": 1, "idx": 1,
"in_create": 1, "in_create": 1,
"issingle": 1, "issingle": 1,
"modified": "2015-02-05 05:11:43.010625", "modified": "2015-06-05 11:44:31.629114",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Production Planning Tool", "name": "Production Planning Tool",

View File

@@ -161,3 +161,9 @@ erpnext.patches.v5_0.set_footer_address
execute:frappe.db.set_value("Backup Manager", None, "send_backups_to_dropbox", 1 if frappe.db.get_value("Backup Manager", None, "upload_backups_to_dropbox") in ("Daily", "Weekly") else 0) execute:frappe.db.set_value("Backup Manager", None, "send_backups_to_dropbox", 1 if frappe.db.get_value("Backup Manager", None, "upload_backups_to_dropbox") in ("Daily", "Weekly") else 0)
execute:frappe.db.sql_list("delete from `tabDocPerm` where parent='Issue' and modified_by='Administrator' and role='Guest'") execute:frappe.db.sql_list("delete from `tabDocPerm` where parent='Issue' and modified_by='Administrator' and role='Guest'")
erpnext.patches.v5_0.update_item_and_description_again erpnext.patches.v5_0.update_item_and_description_again
erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party
erpnext.patches.v5_0.portal_fixes
erpnext.patches.v5_0.reset_values_in_tools
execute:frappe.delete_doc("Page", "users")
erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again
erpnext.patches.v5_0.index_on_account_and_gl_entry

View File

@@ -0,0 +1,22 @@
from __future__ import unicode_literals
import frappe
def execute():
index_map = {
"Account": ["parent_account", "lft", "rgt"],
"GL Entry": ["posting_date", "account", 'party', "voucher_no"]
}
for dt, indexes in index_map.items():
existing_indexes = [d.Key_name for d in frappe.db.sql("""show index from `tab{0}`
where Column_name != 'name'""".format(dt), as_dict=1)]
for old in existing_indexes:
if old in ("parent", "group_or_ledger", "is_pl_account", "debit_or_credit", "account_name", "company"):
frappe.db.sql("alter table `tab{0}` drop index {1}".format(dt, old))
existing_indexes.remove(old)
for new in indexes:
if new not in existing_indexes:
frappe.db.sql("alter table `tab{0}` add index ({1})".format(dt, new))

View File

@@ -0,0 +1,6 @@
import frappe
import erpnext.setup.install
def execute():
frappe.reload_doc("website", "doctype", "web_form_field", force=True)
erpnext.setup.install.add_web_forms()

View File

@@ -0,0 +1,26 @@
# 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 frappe
def execute():
je_list = frappe.db.sql_list("""
select par.name from `tabJournal Entry` par
where par.docstatus=1 and par.creation > '2015-03-01'
and (select count(distinct child.party) from `tabJournal Entry Account` child
where par.name=child.parent and ifnull(child.party, '') != '') > 1
""")
for d in je_list:
# delete existing gle
frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d)
# repost gl entries
je = frappe.get_doc("Journal Entry", d)
je.make_gl_entries()
if je_list:
print je_list

View File

@@ -0,0 +1,11 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
for dt in ["Payment Tool", "Bank Reconciliation", "Payment Reconciliation", "Leave Control Panel",
"Salary Manager", "Upload Attenadance", "Production Planning Tool", "BOM Replace Tool"]:
frappe.db.sql("delete from `tabSingles` where doctype=%s", dt)

View File

@@ -0,0 +1,18 @@
import frappe
def execute():
pro_order_qty_transferred = frappe._dict()
for se in frappe.db.sql("""select production_order, sum(fg_completed_qty) as transferred_qty
from `tabStock Entry`
where docstatus=1 and ifnull(production_order, '') != ''
and purpose = 'Material Transfer for Manufacture'
group by production_order""", as_dict=1):
pro_order_qty_transferred.setdefault(se.production_order, se.transferred_qty)
for d in frappe.get_all("Production Order", filters={"docstatus": 1}, fields=["name", "qty"]):
if d.name in pro_order_qty_transferred:
material_transferred_for_manufacturing = pro_order_qty_transferred.get(d.name) \
if pro_order_qty_transferred.get(d.name) <= d.qty else d.qty
frappe.db.sql("""update `tabProduction Order` set material_transferred_for_manufacturing=%s
where name=%s""", (material_transferred_for_manufacturing, d.name))

View File

@@ -0,0 +1 @@
cur_frm.add_fetch('employee', 'employee_name', 'employee_name');

View File

@@ -2,7 +2,7 @@
"allow_copy": 0, "allow_copy": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "Activity Cost - .#", "autoname": "AC-.#####",
"creation": "2015-03-23 02:00:21.861546", "creation": "2015-03-23 02:00:21.861546",
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
@@ -31,11 +31,12 @@
}, },
{ {
"fieldname": "employee_name", "fieldname": "employee_name",
"fieldtype": "Read Only", "fieldtype": "Data",
"label": "Employee Name", "label": "Employee Name",
"options": "employee.employee_name", "options": "",
"permlevel": 0, "permlevel": 0,
"precision": "" "precision": "",
"read_only": 1
}, },
{ {
"fieldname": "column_break_2", "fieldname": "column_break_2",
@@ -135,7 +136,7 @@
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"modified": "2015-04-14 02:08:33.690406", "modified": "2015-06-11 06:50:47.999788",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Projects", "module": "Projects",
"name": "Activity Cost", "name": "Activity Cost",

View File

@@ -15,6 +15,8 @@ class ActivityCost(Document):
self.check_unique() self.check_unique()
def set_title(self): def set_title(self):
if not self.employee_name:
self.employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
self.title = _("{0} for {1}").format(self.employee_name, self.activity_type) self.title = _("{0} for {1}").format(self.employee_name, self.activity_type)
def check_unique(self): def check_unique(self):

View File

@@ -15,7 +15,8 @@ class Project(Document):
def onload(self): def onload(self):
"""Load project tasks for quick view""" """Load project tasks for quick view"""
for task in frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc"): if not self.get("tasks"):
for task in self.get_tasks():
self.append("tasks", { self.append("tasks", {
"title": task.subject, "title": task.subject,
"status": task.status, "status": task.status,
@@ -25,6 +26,12 @@ class Project(Document):
"task_id": task.name "task_id": task.name
}) })
def __setup__(self):
self.onload()
def get_tasks(self):
return frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc")
def validate(self): def validate(self):
self.validate_dates() self.validate_dates()
self.sync_tasks() self.sync_tasks()

View File

@@ -29,6 +29,10 @@ class Task(Document):
def validate(self): def validate(self):
self.validate_dates() self.validate_dates()
if self.status!=self.get_db_value("status") and self.status == "Closed":
from frappe.desk.form.assign_to import clear
clear(self.doctype, self.name)
def validate_dates(self): def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date): if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'")) frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))

View File

@@ -146,3 +146,34 @@ class TestTask(unittest.TestCase):
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26')) self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28')) self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
def test_close_assignment(self):
task = frappe.new_doc("Task")
task.subject = "Test Close Assignment"
task.insert()
def assign():
from frappe.desk.form import assign_to
assign_to.add({
"assign_to": "test@example.com",
"doctype": task.doctype,
"name": task.name,
"description": "Close this task"
})
def get_owner_and_status():
return frappe.db.get_value("ToDo", filters={"reference_type": task.doctype, "reference_name": task.name,
"description": "Close this task"}, fieldname=("owner", "status"), as_dict=True)
assign()
todo = get_owner_and_status()
self.assertEquals(todo.owner, "test@example.com")
self.assertEquals(todo.status, "Open")
# assignment should be
task.load_from_db()
task.status = "Closed"
task.save()
todo = get_owner_and_status()
self.assertEquals(todo.owner, "test@example.com")
self.assertEquals(todo.status, "Closed")

View File

@@ -195,8 +195,6 @@ class TimeLog(Document):
if self.for_manufacturing: if self.for_manufacturing:
if not self.production_order: if not self.production_order:
frappe.throw(_("Production Order is Mandatory")) frappe.throw(_("Production Order is Mandatory"))
if not self.operation:
frappe.throw(_("Operation is Mandatory"))
if not self.completed_qty: if not self.completed_qty:
self.completed_qty = 0 self.completed_qty = 0

View File

@@ -105,6 +105,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
} }
}, },
barcode: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.barcode=="" || d.barcode==null) {
// barcode cleared, remove item
d.item_code = "";
}
this.item_code(doc, cdt, cdn);
},
item_code: function(doc, cdt, cdn) { item_code: function(doc, cdt, cdn) {
var me = this; var me = this;
var item = frappe.get_doc(cdt, cdn); var item = frappe.get_doc(cdt, cdn);

View File

@@ -81,7 +81,8 @@ erpnext.feature_setup.feature_dict = {
'Item': {'fields': ['barcode']}, 'Item': {'fields': ['barcode']},
'Delivery Note': {'items': ['barcode']}, 'Delivery Note': {'items': ['barcode']},
'Sales Invoice': {'items': ['barcode']}, 'Sales Invoice': {'items': ['barcode']},
'Stock Entry': {'items': ['barcode']} 'Stock Entry': {'items': ['barcode']},
'Purchase Receipt': {'items': ['barcode']}
}, },
'fs_item_group_in_details': { 'fs_item_group_in_details': {
'Delivery Note': {'items':['item_group']}, 'Delivery Note': {'items':['item_group']},

View File

@@ -139,7 +139,7 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
if(sl.voucher_type=="Stock Reconciliation") { if(sl.voucher_type=="Stock Reconciliation") {
var diff = (sl.qty_after_transaction * sl.valuation_rate) - item.closing_qty_value; var diff = (sl.qty_after_transaction * sl.valuation_rate) - item.closing_qty_value;
wh.fifo_stack.push([sl.qty_after_transaction, sl.valuation_rate, sl.posting_date]); wh.fifo_stack = [[sl.qty_after_transaction, sl.valuation_rate, sl.posting_date]];
wh.balance_qty = sl.qty_after_transaction; wh.balance_qty = sl.qty_after_transaction;
wh.balance_value = sl.valuation_rate * sl.qty_after_transaction; wh.balance_value = sl.valuation_rate * sl.qty_after_transaction;
} else { } else {
@@ -167,7 +167,6 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
}, },
update_groups: function() { update_groups: function() {
var me = this; var me = this;
$.each(this.data, function(i, item) { $.each(this.data, function(i, item) {
// update groups // update groups
if(!item.is_group && me.apply_filter(item, "brand")) { if(!item.is_group && me.apply_filter(item, "brand")) {

View File

@@ -55,7 +55,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
@@ -298,12 +298,13 @@
}, },
{ {
"fieldname": "prevdoc_doctype", "fieldname": "prevdoc_doctype",
"fieldtype": "Data", "fieldtype": "Link",
"hidden": 1, "hidden": 1,
"label": "Against Doctype", "label": "Against Doctype",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "prevdoc_doctype", "oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "DocType",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_width": "150px", "print_width": "150px",
@@ -313,11 +314,12 @@
}, },
{ {
"fieldname": "prevdoc_docname", "fieldname": "prevdoc_docname",
"fieldtype": "Data", "fieldtype": "Dynamic Link",
"label": "Against Docname", "label": "Against Docname",
"no_copy": 1, "no_copy": 1,
"oldfieldname": "prevdoc_docname", "oldfieldname": "prevdoc_docname",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "prevdoc_doctype",
"permlevel": 0, "permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_width": "150px", "print_width": "150px",
@@ -390,7 +392,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:15.474119", "modified": "2015-06-02 14:18:00.266748",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Quotation Item", "name": "Quotation Item",

View File

@@ -8,6 +8,13 @@ frappe.query_reports["Customers Not Buying Since Long Time"] = {
"label": __("Days Since Last Order"), "label": __("Days Since Last Order"),
"fieldtype": "Int", "fieldtype": "Int",
"default": 60 "default": 60
},
{
"fieldname":"doctype",
"label": __("Doctype"),
"fieldtype": "Select",
"default": "Sales Order",
"options": "Sales Order\nSales Invoice"
} }
] ]
} }

View File

@@ -10,41 +10,51 @@ def execute(filters=None):
if not filters: filters ={} if not filters: filters ={}
days_since_last_order = filters.get("days_since_last_order") days_since_last_order = filters.get("days_since_last_order")
doctype = filters.get("doctype")
if cint(days_since_last_order) <= 0: if cint(days_since_last_order) <= 0:
frappe.throw(_("'Days Since Last Order' must be greater than or equal to zero")) frappe.throw(_("'Days Since Last Order' must be greater than or equal to zero"))
columns = get_columns() columns = get_columns()
customers = get_so_details() customers = get_sales_details(doctype)
data = [] data = []
for cust in customers: for cust in customers:
if cint(cust[8]) >= cint(days_since_last_order): if cint(cust[8]) >= cint(days_since_last_order):
cust.insert(7,get_last_so_amt(cust[0])) cust.insert(7,get_last_sales_amt(cust[0], doctype))
data.append(cust) data.append(cust)
return columns, data return columns, data
def get_so_details(): def get_sales_details(doctype):
cond = """sum(so.base_net_total) as 'total_order_considered',
max(so.posting_date) as 'last_order_date',
DATEDIFF(CURDATE(), max(so.posting_date)) as 'days_since_last_order' """
if doctype == "Sales Order":
cond = """sum(if(so.status = "Stopped",
so.base_net_total * so.per_delivered/100,
so.base_net_total)) as 'total_order_considered',
max(so.transaction_date) as 'last_order_date',
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'"""
return frappe.db.sql("""select return frappe.db.sql("""select
cust.name, cust.name,
cust.customer_name, cust.customer_name,
cust.territory, cust.territory,
cust.customer_group, cust.customer_group,
count(distinct(so.name)) as 'num_of_order', count(distinct(so.name)) as 'num_of_order',
sum(base_net_total) as 'total_order_value', sum(base_net_total) as 'total_order_value', {0}
sum(if(so.status = "Stopped", from `tabCustomer` cust, `tab{1}` so
so.base_net_total * so.per_delivered/100,
so.base_net_total)) as 'total_order_considered',
max(so.transaction_date) as 'last_sales_order_date',
DATEDIFF(CURDATE(), max(so.transaction_date)) as 'days_since_last_order'
from `tabCustomer` cust, `tabSales Order` so
where cust.name = so.customer and so.docstatus = 1 where cust.name = so.customer and so.docstatus = 1
group by cust.name group by cust.name
order by 'days_since_last_order' desc """,as_list=1) order by 'days_since_last_order' desc """.format(cond, doctype), as_list=1)
def get_last_so_amt(customer): def get_last_sales_amt(customer, doctype):
res = frappe.db.sql("""select base_net_total from `tabSales Order` cond = "posting_date"
where customer ='%(customer)s' and docstatus = 1 order by transaction_date desc if doctype =="Sales Order":
limit 1""" % {'customer': frappe.db.escape(customer)}) cond = "transaction_date"
res = frappe.db.sql("""select base_net_total from `tab{0}`
where customer = %s and docstatus = 1 order by {1} desc
limit 1""".format(doctype, cond), customer)
return res and res[0][0] or 0 return res and res[0][0] or 0
@@ -58,6 +68,6 @@ def get_columns():
_("Total Order Value") + ":Currency:120", _("Total Order Value") + ":Currency:120",
_("Total Order Considered") + ":Currency:160", _("Total Order Considered") + ":Currency:160",
_("Last Order Amount") + ":Currency:160", _("Last Order Amount") + ":Currency:160",
_("Last Sales Order Date") + ":Date:160", _("Last Order Date") + ":Date:160",
_("Days Since Last Order") + "::160" _("Days Since Last Order") + "::160"
] ]

View File

@@ -124,15 +124,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
this.apply_pricing_rule(); this.apply_pricing_rule();
}, },
barcode: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.barcode=="" || d.barcode==null) {
// barcode cleared, remove item
d.item_code = "";
}
this.item_code(doc, cdt, cdn);
},
selling_price_list: function() { selling_price_list: function() {
this.apply_price_list(); this.apply_price_list();
}, },

View File

@@ -124,9 +124,9 @@ erpnext.company.setup_queries = function(frm) {
["default_cash_account", {"account_type": "Cash"}], ["default_cash_account", {"account_type": "Cash"}],
["default_receivable_account", {"account_type": "Receivable"}], ["default_receivable_account", {"account_type": "Receivable"}],
["default_payable_account", {"account_type": "Payable"}], ["default_payable_account", {"account_type": "Payable"}],
["default_expense_account", {"report_type": "Profit and Loss"}], ["default_expense_account", {"root_type": "Expense"}],
["default_income_account", {"report_type": "Profit and Loss"}], ["default_income_account", {"root_type": "Income"}],
["round_off_account", {"account_type": "Profit and Loss"}], ["round_off_account", {"root_type": "Expense"}],
["cost_center", {}], ["cost_center", {}],
["round_off_cost_center", {}] ["round_off_cost_center", {}]
], function(i, v) { ], function(i, v) {
@@ -135,8 +135,8 @@ erpnext.company.setup_queries = function(frm) {
if (sys_defaults.auto_accounting_for_stock) { if (sys_defaults.auto_accounting_for_stock) {
$.each([ $.each([
["stock_adjustment_account", {"report_type": "Profit and Loss"}], ["stock_adjustment_account", {"root_type": "Expense"}],
["expenses_included_in_valuation", {"report_type": "Profit and Loss"}], ["expenses_included_in_valuation", {"root_type": "Expense"}],
["stock_received_but_not_billed", {"report_type": "Balance Sheet"}] ["stock_received_but_not_billed", {"report_type": "Balance Sheet"}]
], function(i, v) { ], function(i, v) {
erpnext.company.set_custom_query(frm, v); erpnext.company.set_custom_query(frm, v);
@@ -146,10 +146,9 @@ erpnext.company.setup_queries = function(frm) {
erpnext.company.set_custom_query = function(frm, v) { erpnext.company.set_custom_query = function(frm, v) {
var filters = { var filters = {
"company": frm.doc.company, "company": frm.doc.name,
"is_group": 0 "is_group": 0
}; };
for (var key in v[1]) for (var key in v[1])
filters[key] = v[1][key]; filters[key] = v[1][key];

View File

@@ -27,12 +27,7 @@ def delete_for_doctype(doctype, company_name):
company_fieldname = meta.get("fields", {"fieldtype": "Link", company_fieldname = meta.get("fields", {"fieldtype": "Link",
"options": "Company"})[0].fieldname "options": "Company"})[0].fieldname
if meta.issingle: if not meta.issingle:
single = frappe.get_doc(doctype, doctype)
single.set(company_fieldname, "")
single.flags.ignore_mandatory = True
single.save()
else:
if not meta.istable: if not meta.istable:
# delete children # delete children
for df in meta.get_table_fields(): for df in meta.get_table_fields():

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
import urllib
from frappe.utils.nestedset import NestedSet from frappe.utils.nestedset import NestedSet
from frappe.website.website_generator import WebsiteGenerator from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache from frappe.website.render import clear_cache
@@ -91,7 +91,7 @@ def get_item_for_list_in_html(context):
# add missing absolute link in files # add missing absolute link in files
# user may forget it during upload # user may forget it during upload
if (context.get("website_image") or "").startswith("files/"): if (context.get("website_image") or "").startswith("files/"):
context["website_image"] = "/" + context["website_image"] context["website_image"] = "/" + urllib.quote(context["website_image"])
return frappe.get_template("templates/includes/product_in_grid.html").render(context) return frappe.get_template("templates/includes/product_in_grid.html").render(context)
def get_group_item_count(item_group): def get_group_item_count(item_group):

View File

@@ -12,7 +12,6 @@ from frappe.model.document import Document
class NamingSeriesNotSetError(frappe.ValidationError): pass class NamingSeriesNotSetError(frappe.ValidationError): pass
class NamingSeries(Document): class NamingSeries(Document):
def get_transactions(self, arg=None): def get_transactions(self, arg=None):
doctypes = list(set(frappe.db.sql_list("""select parent doctypes = list(set(frappe.db.sql_list("""select parent
from `tabDocField` where fieldname='naming_series'""") from `tabDocField` where fieldname='naming_series'""")
@@ -50,7 +49,7 @@ class NamingSeries(Document):
self.set_series_for(self.select_doc_for_series, series_list) self.set_series_for(self.select_doc_for_series, series_list)
# create series # create series
map(self.insert_series, [d.split('.')[0] for d in series_list]) map(self.insert_series, [d.split('.')[0] for d in series_list if d.strip()])
msgprint(_("Series Updated")) msgprint(_("Series Updated"))

View File

@@ -0,0 +1,167 @@
[
{
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 1,
"allow_multiple": 1,
"breadcrumbs": null,
"doc_type": "Address",
"docstatus": 0,
"doctype": "Web Form",
"introduction_text": null,
"login_required": 1,
"modified": "2015-06-01 06:53:43.699336",
"name": "addresses",
"page_name": "addresses",
"published": 1,
"success_message": null,
"success_url": "/addresses",
"title": "Addresses",
"web_form_fields": [
{
"default": null,
"description": "",
"fieldname": "address_title",
"fieldtype": "Data",
"hidden": 0,
"label": "Address Title",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "address_type",
"fieldtype": "Select",
"hidden": 0,
"label": "Address Type",
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther",
"read_only": 0,
"reqd": 1
},
{
"default": null,
"description": null,
"fieldname": "address_line1",
"fieldtype": "Data",
"hidden": 0,
"label": "Address Line 1",
"options": null,
"read_only": 0,
"reqd": 1
},
{
"default": null,
"description": null,
"fieldname": "address_line2",
"fieldtype": "Data",
"hidden": 0,
"label": "Address Line 2",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "city",
"fieldtype": "Data",
"hidden": 0,
"label": "City/Town",
"options": null,
"read_only": 0,
"reqd": 1
},
{
"default": null,
"description": null,
"fieldname": "state",
"fieldtype": "Data",
"hidden": 0,
"label": "State",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "pincode",
"fieldtype": "Data",
"hidden": 0,
"label": "Pincode",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "country",
"fieldtype": "Data",
"hidden": 0,
"label": "Country",
"options": "Country",
"read_only": 0,
"reqd": 1
},
{
"default": null,
"description": null,
"fieldname": null,
"fieldtype": "Column Break",
"hidden": null,
"label": null,
"options": null,
"read_only": null,
"reqd": null
},
{
"default": null,
"description": null,
"fieldname": "email_id",
"fieldtype": "Data",
"hidden": 0,
"label": "Email Id",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "phone",
"fieldtype": "Data",
"hidden": 0,
"label": "Phone",
"options": null,
"read_only": 0,
"reqd": 1
},
{
"default": "0",
"description": "",
"fieldname": "is_primary_address",
"fieldtype": "Check",
"hidden": 0,
"label": "Preferred Billing Address",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": "0",
"description": "",
"fieldname": "is_shipping_address",
"fieldtype": "Check",
"hidden": 0,
"label": "Preferred Shipping Address",
"options": null,
"read_only": 0,
"reqd": 0
}
],
"web_page_link_text": null
}
]

View File

@@ -0,0 +1,68 @@
[
{
"allow_comments": 1,
"allow_delete": 1,
"allow_edit": 1,
"allow_multiple": 1,
"breadcrumbs": "[{\"title\":\"Issues\", \"name\":\"issues\"}]",
"doc_type": "Issue",
"docstatus": 0,
"doctype": "Web Form",
"introduction_text": null,
"login_required": 1,
"modified": "2015-06-01 08:14:26.350792",
"name": "issues",
"page_name": "issues",
"published": 1,
"success_message": "",
"success_url": "/issues",
"title": "Issues",
"web_form_fields": [
{
"default": null,
"description": null,
"fieldname": "subject",
"fieldtype": "Data",
"hidden": 0,
"label": "Subject",
"options": null,
"read_only": 0,
"reqd": 1
},
{
"default": "Open",
"description": null,
"fieldname": "status",
"fieldtype": "Select",
"hidden": null,
"label": "Status",
"options": "Open\nReplied\nHold\nClosed",
"read_only": 1,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"label": "Description",
"options": null,
"read_only": 0,
"reqd": 0
},
{
"default": null,
"description": null,
"fieldname": "attachment",
"fieldtype": "Attach",
"hidden": null,
"label": "Attachment",
"options": null,
"read_only": null,
"reqd": null
}
],
"web_page_link_text": null
}
]

View File

@@ -15,6 +15,7 @@ def after_install():
feature_setup() feature_setup()
from erpnext.setup.page.setup_wizard.setup_wizard import add_all_roles_to from erpnext.setup.page.setup_wizard.setup_wizard import add_all_roles_to
add_all_roles_to("Administrator") add_all_roles_to("Administrator")
add_web_forms()
frappe.db.commit() frappe.db.commit()
def feature_setup(): def feature_setup():
@@ -48,3 +49,12 @@ def set_single_defaults():
pass pass
frappe.db.set_default("date_format", "dd-mm-yyyy") frappe.db.set_default("date_format", "dd-mm-yyyy")
def add_web_forms():
"""Import web forms for Issues and Addresses"""
from frappe.modules.import_file import import_file_by_path
import_file_by_path(frappe.get_app_path("erpnext", "setup/fixtures/web_form/issues.json"),
data_import=True)
import_file_by_path(frappe.get_app_path("erpnext", "setup/fixtures/web_form/addresses.json"),
data_import=True)

View File

@@ -215,6 +215,7 @@ $.extend(erpnext.wiz, {
slide.get_field("language") slide.get_field("language")
.set_input(erpnext.wiz.welcome.data.default_language || "english"); .set_input(erpnext.wiz.welcome.data.default_language || "english");
moment.locale("en");
} }
}); });
}, },

View File

@@ -5,13 +5,14 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import throw, _ from frappe import throw, _
import frappe.defaults import frappe.defaults
from frappe.utils import flt, get_fullname, fmt_money, cstr from frappe.utils import cint, flt, get_fullname, fmt_money, cstr
from erpnext.utilities.doctype.address.address import get_address_display from erpnext.utilities.doctype.address.address import get_address_display
from frappe.utils.nestedset import get_root_of from frappe.utils.nestedset import get_root_of
class WebsitePriceListMissingError(frappe.ValidationError): pass class WebsitePriceListMissingError(frappe.ValidationError): pass
def set_cart_count(quotation=None): def set_cart_count(quotation=None):
if cint(frappe.db.get_singles_value("Shopping Cart Settings", "enabled")):
if not quotation: if not quotation:
quotation = _get_cart_quotation() quotation = _get_cart_quotation()
cart_count = cstr(len(quotation.get("items"))) cart_count = cstr(len(quotation.get("items")))
@@ -29,7 +30,7 @@ def get_cart_quotation(doc=None):
return { return {
"doc": decorate_quotation_doc(doc), "doc": decorate_quotation_doc(doc),
"addresses": [{"name": address.name, "display": address.display} "addresses": [{"name": address.name, "display": address.display}
for address in get_address_docs(party)], for address in get_address_docs(party=party)],
"shipping_rules": get_applicable_shipping_rules(party) "shipping_rules": get_applicable_shipping_rules(party)
} }
@@ -281,12 +282,13 @@ def get_lead_or_customer():
return lead_doc return lead_doc
def get_address_docs(party=None): def get_address_docs(doctype=None, txt=None, filters=None, limit_start=0, limit_page_length=20, party=None):
if not party: if not party:
party = get_lead_or_customer() party = get_lead_or_customer()
address_docs = frappe.db.sql("""select * from `tabAddress` address_docs = frappe.db.sql("""select * from `tabAddress`
where `%s`=%s order by name""" % (party.doctype.lower(), "%s"), party.name, where `{0}`=%s order by name limit {1}, {2}""".format(party.doctype.lower(),
limit_start, limit_page_length), party.name,
as_dict=True, update={"doctype": "Address"}) as_dict=True, update={"doctype": "Address"})
for address in address_docs: for address in address_docs:

View File

@@ -8,7 +8,7 @@ import frappe
from frappe import _, msgprint from frappe import _, msgprint
from frappe.utils import comma_and from frappe.utils import comma_and
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils.nestedset import get_ancestors_of from frappe.utils.nestedset import get_ancestors_of, get_root_of
from erpnext.utilities.doctype.address.address import get_territory_from_address from erpnext.utilities.doctype.address.address import get_territory_from_address
class ShoppingCartSetupError(frappe.ValidationError): pass class ShoppingCartSetupError(frappe.ValidationError): pass
@@ -42,7 +42,7 @@ class ShoppingCartSettings(Document):
return territory_name_map return territory_name_map
def validate_price_lists(self): def validate_price_lists(self):
territory_name_map = self.validate_overlapping_territories("price_lists", "selling_price_list") self.validate_overlapping_territories("price_lists", "selling_price_list")
# validate that a Shopping Cart Price List exists for the default territory as a catch all! # validate that a Shopping Cart Price List exists for the default territory as a catch all!
price_list_for_default_territory = self.get_name_from_territory(self.default_territory, "price_lists", price_list_for_default_territory = self.get_name_from_territory(self.default_territory, "price_lists",
@@ -131,7 +131,8 @@ class ShoppingCartSettings(Document):
def get_price_list(self, billing_territory): def get_price_list(self, billing_territory):
price_list = self.get_name_from_territory(billing_territory, "price_lists", "selling_price_list") price_list = self.get_name_from_territory(billing_territory, "price_lists", "selling_price_list")
if not (price_list and price_list[0]): if not (price_list and price_list[0]):
price_list = self.get_name_from_territory(self.default_territory, "price_lists", "selling_price_list") price_list = self.get_name_from_territory(self.default_territory or get_root_of("Territory"),
"price_lists", "selling_price_list")
return price_list and price_list[0] or None return price_list and price_list[0] or None
@@ -165,7 +166,7 @@ def is_cart_enabled():
return get_shopping_cart_settings().enabled return get_shopping_cart_settings().enabled
def get_default_territory(): def get_default_territory():
return get_shopping_cart_settings().default_territory return get_shopping_cart_settings().default_territory or get_root_of("Territory")
def check_shopping_cart_enabled(): def check_shopping_cart_enabled():
if not get_shopping_cart_settings().enabled: if not get_shopping_cart_settings().enabled:

View File

@@ -6,7 +6,6 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
import frappe.defaults import frappe.defaults
from frappe.utils import cint
from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import is_cart_enabled from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import is_cart_enabled
def show_cart_count(): def show_cart_count():
@@ -44,6 +43,6 @@ def update_my_account_context(context):
{"label": _("Orders"), "url": "orders"}, {"label": _("Orders"), "url": "orders"},
{"label": _("Invoices"), "url": "invoices"}, {"label": _("Invoices"), "url": "invoices"},
{"label": _("Shipments"), "url": "shipments"}, {"label": _("Shipments"), "url": "shipments"},
# {"label": _("Issues"), "url": "tickets"}, {"label": _("Issues"), "url": "issues"},
{"label": _("Addresses"), "url": "addresses"}, {"label": _("Addresses"), "url": "addresses"},
]) ])

View File

@@ -65,7 +65,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
@@ -523,7 +523,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:16.946934", "modified": "2015-06-02 14:18:34.512236",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Delivery Note Item", "name": "Delivery Note Item",

View File

@@ -90,7 +90,7 @@ class TestItem(unittest.TestCase):
"income_account": "Sales - _TC", "income_account": "Sales - _TC",
"expense_account": "_Test Account Cost for Goods Sold - _TC", "expense_account": "_Test Account Cost for Goods Sold - _TC",
"cost_center": "_Test Cost Center 2 - _TC", "cost_center": "_Test Cost Center 2 - _TC",
"qty": 0.0, "qty": 1.0,
"price_list_rate": 100.0, "price_list_rate": 100.0,
"base_price_list_rate": 0.0, "base_price_list_rate": 0.0,
"discount_percentage": 0.0, "discount_percentage": 0.0,

View File

@@ -221,7 +221,7 @@
"icon": "icon-ticket", "icon": "icon-ticket",
"idx": 1, "idx": 1,
"is_submittable": 1, "is_submittable": 1,
"modified": "2015-05-27 15:36:06.818491", "modified": "2015-06-09 05:47:05.934432",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Material Request", "name": "Material Request",

View File

@@ -6,7 +6,13 @@ frappe.listview_settings['Material Request'] = {
} else if(doc.docstatus==1 && flt(doc.per_ordered) < 100) { } else if(doc.docstatus==1 && flt(doc.per_ordered) < 100) {
return [__("Pending"), "orange", "per_ordered,<,100"]; return [__("Pending"), "orange", "per_ordered,<,100"];
} else if(doc.docstatus==1 && flt(doc.per_ordered) == 100) { } else if(doc.docstatus==1 && flt(doc.per_ordered) == 100) {
if (doc.material_request_type == "Purchase") {
return [__("Ordered"), "green", "per_ordered,=,100"]; return [__("Ordered"), "green", "per_ordered,=,100"];
} else if (doc.material_request_type == "Material Transfer") {
return [__("Transfered"), "green", "per_ordered,=,100"];
} else if (doc.material_request_type == "Material Issue") {
return [__("Issued"), "green", "per_ordered,=,100"];
}
} }
} }
}; };

View File

@@ -48,7 +48,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text", "fieldtype": "Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Text", "oldfieldtype": "Text",
@@ -264,7 +264,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-02-19 01:07:00.695393", "modified": "2015-06-02 14:19:45.611733",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Material Request Item", "name": "Material Request Item",

View File

@@ -4,6 +4,19 @@
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"fields": [ "fields": [
{
"fieldname": "barcode",
"fieldtype": "Data",
"label": "Barcode",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "section_break_2",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{ {
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
@@ -49,7 +62,7 @@
{ {
"fieldname": "description", "fieldname": "description",
"fieldtype": "Text", "fieldtype": "Text",
"in_list_view": 1, "in_list_view": 0,
"label": "Description", "label": "Description",
"oldfieldname": "description", "oldfieldname": "description",
"oldfieldtype": "Text", "oldfieldtype": "Text",
@@ -642,7 +655,7 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2015-05-27 02:47:16.086625", "modified": "2015-06-08 08:21:18.024324",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Purchase Receipt Item", "name": "Purchase Receipt Item",

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
import frappe.defaults import frappe.defaults
from frappe.utils import cstr, cint, flt, comma_or, nowdate, get_datetime from frappe.utils import cstr, cint, flt, comma_or, get_datetime
from frappe import _ from frappe import _
from erpnext.stock.utils import get_incoming_rate from erpnext.stock.utils import get_incoming_rate
@@ -112,7 +112,7 @@ class StockEntry(StockController):
for f in ("uom", "stock_uom", "description", "item_name", "expense_account", for f in ("uom", "stock_uom", "description", "item_name", "expense_account",
"cost_center", "conversion_factor"): "cost_center", "conversion_factor"):
if f not in ["expense_account", "cost_center"] or not item.get(f): if f in ["stock_uom", "conversion_factor"] or not item.get(f):
item.set(f, item_details.get(f)) item.set(f, item_details.get(f))
if self.difference_account: if self.difference_account:
@@ -190,6 +190,8 @@ class StockEntry(StockController):
frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture")) frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture"))
# check for double entry # check for double entry
if self.purpose=="Manufacture": if self.purpose=="Manufacture":
if not self.fg_completed_qty:
frappe.throw(_("For Quantity (Manufactured Qty) is mandatory"))
self.check_if_operations_completed() self.check_if_operations_completed()
self.check_duplicate_entry_for_production_order() self.check_duplicate_entry_for_production_order()
elif self.purpose != "Material Transfer": elif self.purpose != "Material Transfer":
@@ -378,11 +380,22 @@ class StockEntry(StockController):
def validate_finished_goods(self): def validate_finished_goods(self):
"""validation: finished good quantity should be same as manufacturing quantity""" """validation: finished good quantity should be same as manufacturing quantity"""
items_with_target_warehouse = []
for d in self.get('items'): for d in self.get('items'):
if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty): if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty):
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \ frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
format(d.idx, d.transfer_qty, self.fg_completed_qty)) format(d.idx, d.transfer_qty, self.fg_completed_qty))
if self.production_order and self.purpose == "Manufacture" and d.t_warehouse:
items_with_target_warehouse.append(d.item_code)
if self.production_order and self.purpose == "Manufacture":
production_item = frappe.db.get_value("Production Order",
self.production_order, "production_item")
if production_item not in items_with_target_warehouse:
frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry")
.format(production_item))
def validate_return_reference_doc(self): def validate_return_reference_doc(self):
"""validate item with reference doc""" """validate item with reference doc"""
ref = get_return_doc_and_details(self) ref = get_return_doc_and_details(self)
@@ -399,7 +412,6 @@ class StockEntry(StockController):
# posting date check # posting date check
ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00") ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00")
this_posting_datetime = "%s %s" % (self.posting_date, self.posting_time)
if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime): if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime):
from frappe.utils.dateutils import datetime_in_user_format from frappe.utils.dateutils import datetime_in_user_format
@@ -474,6 +486,7 @@ class StockEntry(StockController):
pro_doc = frappe.get_doc("Production Order", self.production_order) pro_doc = frappe.get_doc("Production Order", self.production_order)
_validate_production_order(pro_doc) _validate_production_order(pro_doc)
pro_doc.run_method("update_status") pro_doc.run_method("update_status")
if self.fg_completed_qty:
pro_doc.run_method("update_production_order_qty") pro_doc.run_method("update_production_order_qty")
if self.purpose == "Manufacture": if self.purpose == "Manufacture":
self.update_planned_qty(pro_doc) self.update_planned_qty(pro_doc)
@@ -546,9 +559,6 @@ class StockEntry(StockController):
return ret return ret
def get_items(self): def get_items(self):
if not self.fg_completed_qty or not self.bom_no:
frappe.throw(_("BOM and Manufacturing Quantity are required"))
self.set('items', []) self.set('items', [])
self.validate_production_order() self.validate_production_order()
@@ -638,17 +648,16 @@ class StockEntry(StockController):
issued_item_qty = self.get_issued_qty() issued_item_qty = self.get_issued_qty()
max_qty = flt(self.pro_doc.qty) max_qty = flt(self.pro_doc.qty)
only_pending_fetched = []
for item in item_dict: for item in item_dict:
pending_to_issue = (max_qty * item_dict[item]["qty"]) - issued_item_qty.get(item, 0) pending_to_issue = (max_qty * item_dict[item]["qty"]) - issued_item_qty.get(item, 0)
desire_to_transfer = flt(self.fg_completed_qty) * item_dict[item]["qty"] desire_to_transfer = flt(self.fg_completed_qty) * item_dict[item]["qty"]
if desire_to_transfer <= pending_to_issue: if desire_to_transfer <= pending_to_issue:
item_dict[item]["qty"] = desire_to_transfer item_dict[item]["qty"] = desire_to_transfer
else: elif pending_to_issue > 0:
item_dict[item]["qty"] = pending_to_issue item_dict[item]["qty"] = pending_to_issue
if pending_to_issue: else:
only_pending_fetched.append(item) item_dict[item]["qty"] = 0
# delete items with 0 qty # delete items with 0 qty
for item in item_dict.keys(): for item in item_dict.keys():
@@ -659,9 +668,6 @@ class StockEntry(StockController):
if not len(item_dict): if not len(item_dict):
frappe.msgprint(_("""All items have already been transferred for this Production Order.""")) frappe.msgprint(_("""All items have already been transferred for this Production Order."""))
elif only_pending_fetched:
frappe.msgprint(_("Pending Items {0} updated").format(only_pending_fetched))
return item_dict return item_dict
def get_issued_qty(self): def get_issued_qty(self):

View File

@@ -163,8 +163,8 @@ def get_basic_details(args, item):
"uom": item.stock_uom, "uom": item.stock_uom,
"min_order_qty": flt(item.min_order_qty) if args.parenttype == "Material Request" else "", "min_order_qty": flt(item.min_order_qty) if args.parenttype == "Material Request" else "",
"conversion_factor": 1.0, "conversion_factor": 1.0,
"qty": args.qty or 0.0, "qty": args.qty or 1.0,
"stock_qty": 0.0, "stock_qty": 1.0,
"price_list_rate": 0.0, "price_list_rate": 0.0,
"base_price_list_rate": 0.0, "base_price_list_rate": 0.0,
"rate": 0.0, "rate": 0.0,

View File

@@ -5,12 +5,12 @@
"doctype": "Report", "doctype": "Report",
"idx": 1, "idx": 1,
"is_standard": "Yes", "is_standard": "Yes",
"modified": "2015-04-07 08:18:14.440193", "modified": "2015-06-10 15:52:49.492144",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Ordered Items To Be Delivered", "name": "Ordered Items To Be Delivered",
"owner": "Administrator", "owner": "Administrator",
"query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\"\nfrom\n `tabSales Order`, `tabSales Order Item`, `tabBin`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\n and `tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse\norder by `tabSales Order`.transaction_date asc", "query": "select \n `tabSales Order`.`name` as \"Sales Order:Link/Sales Order:120\",\n `tabSales Order`.`customer` as \"Customer:Link/Customer:120\",\n `tabSales Order`.`transaction_date` as \"Date:Date\",\n `tabSales Order`.`project_name` as \"Project\",\n `tabSales Order Item`.item_code as \"Item:Link/Item:120\",\n `tabSales Order Item`.qty as \"Qty:Float:140\",\n `tabSales Order Item`.delivered_qty as \"Delivered Qty:Float:140\",\n (`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0)) as \"Qty to Deliver:Float:140\",\n `tabSales Order Item`.base_rate as \"Rate:Float:140\",\n `tabSales Order Item`.base_amount as \"Amount:Float:140\",\n ((`tabSales Order Item`.qty - ifnull(`tabSales Order Item`.delivered_qty, 0))*`tabSales Order Item`.base_rate) as \"Amount to Deliver:Float:140\",\n `tabBin`.actual_qty as \"Available Qty:Float:120\",\n `tabBin`.projected_qty as \"Projected Qty:Float:120\",\n `tabSales Order`.`delivery_date` as \"Expected Delivery Date:Date:120\",\n `tabSales Order Item`.item_name as \"Item Name::150\",\n `tabSales Order Item`.description as \"Description::200\",\n `tabSales Order Item`.item_group as \"Item Group:Link/Item Group:120\",\n `tabSales Order Item`.warehouse as \"Warehouse:Link/Warehouse:200\"\nfrom\n `tabSales Order`, `tabSales Order Item`, `tabBin`\nwhere\n `tabSales Order Item`.`parent` = `tabSales Order`.`name`\n and `tabSales Order`.docstatus = 1\n and `tabSales Order`.status != \"Stopped\"\n and ifnull(`tabSales Order Item`.delivered_qty,0) < ifnull(`tabSales Order Item`.qty,0)\n and `tabBin`.item_code = `tabSales Order Item`.item_code\n and `tabBin`.warehouse = `tabSales Order Item`.warehouse\norder by `tabSales Order`.transaction_date asc",
"ref_doctype": "Delivery Note", "ref_doctype": "Delivery Note",
"report_name": "Ordered Items To Be Delivered", "report_name": "Ordered Items To Be Delivered",
"report_type": "Query Report" "report_type": "Query Report"

View File

@@ -66,7 +66,7 @@
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "Email", "options": "Email",
"permlevel": 0, "permlevel": 0,
"reqd": 1 "reqd": 0
}, },
{ {
"fieldname": "fold", "fieldname": "fold",
@@ -229,11 +229,19 @@
"hidden": 1, "hidden": 1,
"label": "Content Type", "label": "Content Type",
"permlevel": 0 "permlevel": 0
},
{
"fieldname": "attachment",
"fieldtype": "Attach",
"hidden": 1,
"label": "Attachment",
"permlevel": 0,
"precision": ""
} }
], ],
"icon": "icon-ticket", "icon": "icon-ticket",
"idx": 1, "idx": 1,
"modified": "2015-05-28 03:21:04.690112", "modified": "2015-06-01 08:14:01.750421",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Support", "module": "Support",
"name": "Issue", "name": "Issue",

View File

@@ -17,6 +17,8 @@ class Issue(Document):
return "{0}: {1}".format(_(self.status), self.subject) return "{0}: {1}".format(_(self.status), self.subject)
def validate(self): def validate(self):
if not self.raised_by:
self.raised_by = frappe.session.user
self.update_status() self.update_status()
self.set_lead_contact(self.raised_by) self.set_lead_contact(self.raised_by)
@@ -54,7 +56,8 @@ class Issue(Document):
def get_list_context(context=None): def get_list_context(context=None):
return { return {
"title": _("My Issues"), "title": _("My Issues"),
"get_list": get_issue_list "get_list": get_issue_list,
"row_template": "templates/includes/issue_row.html"
} }
def get_issue_list(doctype, txt, filters, limit_start, limit_page_length=20): def get_issue_list(doctype, txt, filters, limit_start, limit_page_length=20):
@@ -84,3 +87,6 @@ def set_multiple_status(names, status):
names = json.loads(names) names = json.loads(names)
for name in names: for name in names:
set_status(name, status) set_status(name, status)
def has_website_permission(doc, ptype, user, verbose=False):
return doc.raised_by==user

View File

@@ -1,6 +1,6 @@
{% $.each(visible_columns || [], function(i, df) { %} {% $.each(visible_columns || [], function(i, df) { %}
{% var val = doc.get_formatted(df.fieldname); {% var val = doc.get_formatted(df.fieldname);
if((df.fieldname !== "description") && val) { %} if((df.fieldname !== "description" && df.fieldname !== "item_name") && val) { %}
<div class="row"> <div class="row">
<div class="col-xs-4 text-ellipsis"> <div class="col-xs-4 text-ellipsis">
<strong title="{%= __(df.label) %}">{%= __(df.label) %}:</strong> <strong title="{%= __(df.label) %}">{%= __(df.label) %}:</strong>

View File

@@ -1,4 +1,4 @@
{% var visible_columns = row.get_visible_columns(["item_code", "item_name", "description", "qty", "rate", "amount", "stock_uom", "uom", "discount_percentage", "schedule_date", "warehouse", "against_sales_order", "sales_order"]); %} {% var visible_columns = row.get_visible_columns(["item_code", "qty", "rate", "amount", "stock_uom", "uom", "discount_percentage", "schedule_date", "warehouse", "against_sales_order", "sales_order"]); %}
{% if(!doc) { %} {% if(!doc) { %}
<div class="row"> <div class="row">
@@ -8,6 +8,7 @@
<div class="col-sm-2 col-xs-4 text-right">{%= __("Amount") %}</div> <div class="col-sm-2 col-xs-4 text-right">{%= __("Amount") %}</div>
</div> </div>
{% } else { %} {% } else { %}
{% var visible_column_fieldnames = $.map(visible_columns, function(x, i) {return x.fieldname}); %}
<div class="row"> <div class="row">
<div class="col-sm-6 col-xs-8"> <div class="col-sm-6 col-xs-8">
{% if(doc.warehouse) { {% if(doc.warehouse) {
@@ -45,8 +46,14 @@
<strong>{%= doc.item_code %}</strong> <strong>{%= doc.item_code %}</strong>
{% } %} {% } %}
{% if(doc.item_name != doc.item_code) { %} {% if(doc.item_name != doc.item_code && in_list(visible_column_fieldnames, "item_name")) { %}
<br>{%= doc.item_name %}{% } %} <br>{%= doc.item_name %}{% } %}
{% if((doc.description != doc.item_code != doc.item_name) &&
in_list(visible_column_fieldnames, "description")) { %}
<br>
<strong>Description: </strong>
{%= doc.get_formatted("description") %}{% } %}
{% include "templates/form_grid/includes/visible_cols.html" %} {% include "templates/form_grid/includes/visible_cols.html" %}
</div> </div>

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