From 6773bc251273855b5352c332116c13e68c0e8847 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 17 Sep 2013 11:56:17 +0530 Subject: [PATCH 001/123] [pos] [minor] added pos in sales order for testing --- .../doctype/sales_invoice/sales_invoice.js | 82 +++++++++---------- .../p03_buying_selling_for_price_list.py | 2 +- public/js/transaction.js | 58 ++++++++++++- selling/doctype/sales_order/sales_order.js | 1 + 4 files changed, 95 insertions(+), 48 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 60f73b5a19..73958fb672 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -82,10 +82,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte cur_frm.cscript.sales_order_btn(); cur_frm.cscript.delivery_note_btn(); } - - // Show POS button only if it enabled from features setup - if(cint(sys_defaults.fs_pos_view)===1) - cur_frm.cscript.pos_btn(); }, sales_order_btn: function() { @@ -125,53 +121,53 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); }, - pos_btn: function() { - if(cur_frm.$pos_btn) - cur_frm.$pos_btn.remove(); + // pos_btn: function() { + // if(cur_frm.$pos_btn) + // cur_frm.$pos_btn.remove(); - if(!cur_frm.pos_active) { - var btn_label = wn._("POS View"), - icon = "icon-desktop"; + // if(!cur_frm.pos_active) { + // var btn_label = wn._("POS View"), + // icon = "icon-desktop"; - cur_frm.cscript.sales_order_btn(); - cur_frm.cscript.delivery_note_btn(); - } else { - var btn_label = wn._("Invoice View"), - icon = "icon-file-text"; + // cur_frm.cscript.sales_order_btn(); + // cur_frm.cscript.delivery_note_btn(); + // } else { + // var btn_label = wn._("Invoice View"), + // icon = "icon-file-text"; - if (cur_frm.doc.docstatus===0) { - this.$delivery_note_btn.remove(); - this.$sales_order_btn.remove(); - } - } + // if (cur_frm.doc.docstatus===0) { + // this.$delivery_note_btn.remove(); + // this.$sales_order_btn.remove(); + // } + // } - cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() { - cur_frm.cscript.toggle_pos(); - cur_frm.cscript.pos_btn(); - }, icon); - }, + // cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() { + // cur_frm.cscript.toggle_pos(); + // cur_frm.cscript.pos_btn(); + // }, icon); + // }, - toggle_pos: function(show) { - if (!this.frm.doc.selling_price_list) - msgprint(wn._("Please select Price List")) - else { - if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return; + // toggle_pos: function(show) { + // if (!this.frm.doc.selling_price_list) + // msgprint(wn._("Please select Price List")) + // else { + // if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return; - // make pos - if(!cur_frm.pos) { - cur_frm.layout.add_view("pos"); - cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm); - } + // // make pos + // if(!cur_frm.pos) { + // cur_frm.layout.add_view("pos"); + // cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm); + // } - // toggle view - cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos"); - cur_frm.pos_active = !cur_frm.pos_active; + // // toggle view + // cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos"); + // cur_frm.pos_active = !cur_frm.pos_active; - // refresh - if(cur_frm.pos_active) - cur_frm.pos.refresh(); - } - }, + // // refresh + // if(cur_frm.pos_active) + // cur_frm.pos.refresh(); + // } + // }, tc_name: function() { this.get_terms(); diff --git a/patches/june_2013/p03_buying_selling_for_price_list.py b/patches/june_2013/p03_buying_selling_for_price_list.py index c251712437..7d222c8e8a 100644 --- a/patches/june_2013/p03_buying_selling_for_price_list.py +++ b/patches/june_2013/p03_buying_selling_for_price_list.py @@ -22,6 +22,6 @@ def execute(): webnotes.conn.set_value("Price List", price_list, "buying_or_selling", buying_or_selling) except MySQLdb.OperationalError, e: if e.args[0] == 1054: - webnotes.conn.set_value("Price List", price_list, "buying_or_selling", "Selling") + webnotes.conn.sql("""update `tabItem Price` set buying_or_selling='Selling' """) else: raise e \ No newline at end of file diff --git a/public/js/transaction.js b/public/js/transaction.js index 387140472c..f7caded328 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -62,6 +62,56 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ erpnext.hide_company(); this.show_item_wise_taxes(); this.set_dynamic_labels(); + + // Show POS button only if it is enabled from features setup + if(cint(sys_defaults.fs_pos_view)===1 && this.frm.doctype!="Material Request") + this.pos_btn(); + }, + + pos_btn: function() { + if(this.$pos_btn) + this.$pos_btn.remove(); + + if(!this.pos_active) { + var btn_label = wn._("POS View"), + icon = "icon-desktop"; + } else { + var btn_label = wn._(this.frm.doctype) + wn._(" View"), + icon = "icon-file-text"; + + + if (this.frm.doc.docstatus===0) { + this.frm.clear_custom_buttons(); + } + } + var me = this; + + this.$pos_btn = this.frm.add_custom_button(btn_label, function() { + me.toggle_pos(); + me.pos_btn(); + }, icon); + }, + + toggle_pos: function(show) { + if (!this.frm.doc.selling_price_list) + msgprint(wn._("Please select Price List")) + else { + if((show===true && this.pos_active) || (show===false && !this.pos_active)) return; + + // make pos + if(!this.pos) { + this.frm.layout.add_view("pos"); + this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm); + } + + // toggle view + this.frm.layout.set_view(this.pos_active ? "" : "pos"); + this.pos_active = !this.pos_active; + + // refresh + if(this.pos_active) + this.frm.pos.refresh(); + } }, validate: function() { @@ -418,10 +468,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ (this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) : false; - // if(!valid_conversion_rate) { - // wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + - // " 1 " + this.frm.doc.currency + " = [?] " + company_currency); - // } + if(!valid_conversion_rate) { + wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + + " 1 " + this.frm.doc.currency + " = [?] " + company_currency); + } }, calculate_taxes_and_totals: function() { diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index 33699f05d8..161e10fe4e 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -12,6 +12,7 @@ cur_frm.cscript.sales_team_fname = "sales_team"; wn.require('app/selling/doctype/sales_common/sales_common.js'); wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js'); wn.require('app/utilities/doctype/sms_control/sms_control.js'); +wn.require('app/accounts/doctype/sales_invoice/pos.js'); erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({ refresh: function(doc, dt, dn) { From a550e7443fa9c1a6ff6f0224db0764dcf7271179 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 17 Sep 2013 18:52:00 +0530 Subject: [PATCH 002/123] [pos] moved pos realted code from sales_invoice.js to transaction.js --- accounts/doctype/sales_invoice/pos.js | 23 ++++++++++--------- .../doctype/sales_invoice/sales_invoice.js | 2 +- public/js/transaction.js | 5 ---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 8837aed14b..67c4b93186 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -96,6 +96,7 @@ erpnext.POS = Class.extend({ }, make_customer: function() { var me = this; + console.log(this.frm); this.customer = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -109,7 +110,7 @@ erpnext.POS = Class.extend({ this.customer.make_input(); this.customer.$input.on("change", function() { if(!me.customer.autocomplete_open) - wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value); + wn.model.set_value(this.frm.doctype, me.frm.docname, "customer", this.value); }); }, make_item_group: function() { @@ -221,8 +222,8 @@ erpnext.POS = Class.extend({ // check whether the item is already added if (no_of_items != 0) { - $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { if (d.item_code == item_code) caught = true; }); @@ -233,15 +234,15 @@ erpnext.POS = Class.extend({ me.update_qty(item_code, 1); } else { - var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries"); + var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", "entries"); child.item_code = item_code; me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); } }, update_qty: function(item_code, qty, textbox_qty) { var me = this; - $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { if (d.item_code == item_code) { if (textbox_qty) { if (qty == 0 && d.item_code == item_code) @@ -265,8 +266,8 @@ erpnext.POS = Class.extend({ // add items var $items = me.wrapper.find("#cart tbody").empty(); - $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries", - "Sales Invoice"), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", + this.frm.doctype), function(i, d) { $(repl('\ %(item_code)s%(item_name)s\ Date: Wed, 18 Sep 2013 11:10:59 +0530 Subject: [PATCH 003/123] remove sql = --- accounts/doctype/account/account.py | 1 - accounts/doctype/bank_reconciliation/bank_reconciliation.py | 1 - accounts/doctype/gl_entry/gl_entry.py | 1 - accounts/doctype/mis_control/mis_control.py | 1 - .../doctype/period_closing_voucher/period_closing_voucher.py | 1 - accounts/doctype/purchase_invoice/purchase_invoice.py | 1 - .../purchase_taxes_and_charges_master.py | 1 - buying/doctype/purchase_common/purchase_common.py | 1 - buying/doctype/purchase_order/purchase_order.py | 1 - buying/doctype/supplier/supplier.py | 1 - home/doctype/feed/feed.py | 1 - hr/doctype/attendance/attendance.py | 1 - hr/doctype/employee/employee.py | 1 - hr/doctype/holiday_list/holiday_list.py | 1 - hr/doctype/leave_allocation/leave_allocation.py | 1 - hr/doctype/leave_control_panel/leave_control_panel.py | 1 - hr/doctype/salary_manager/salary_manager.py | 1 - hr/doctype/salary_slip/salary_slip.py | 1 - hr/doctype/salary_structure/salary_structure.py | 1 - manufacturing/doctype/bom/bom.py | 1 - manufacturing/doctype/production_order/production_order.py | 1 - .../production_planning_tool/production_planning_tool.py | 1 - manufacturing/doctype/workstation/workstation.py | 1 - projects/doctype/task/task.py | 1 - selling/doctype/customer/customer.py | 1 - selling/doctype/lead/lead.py | 1 - selling/doctype/opportunity/opportunity.py | 1 - selling/doctype/quotation/quotation.py | 1 - selling/doctype/sales_order/sales_order.py | 1 - selling/doctype/sms_center/sms_center.py | 1 - setup/doctype/authorization_control/authorization_control.py | 1 - setup/doctype/authorization_rule/authorization_rule.py | 1 - setup/doctype/company/company.py | 1 - setup/doctype/customer_group/customer_group.py | 1 - setup/doctype/email_settings/email_settings.py | 1 - setup/doctype/naming_series/naming_series.py | 1 - setup/doctype/notification_control/notification_control.py | 1 - setup/doctype/print_heading/print_heading.py | 1 - setup/doctype/sales_partner/sales_partner.py | 1 - stock/doctype/bin/bin.py | 1 - stock/doctype/delivery_note/delivery_note.py | 1 - stock/doctype/landed_cost_wizard/landed_cost_wizard.py | 1 - stock/doctype/purchase_receipt/purchase_receipt.py | 1 - stock/doctype/stock_entry/stock_entry.py | 1 - stock/doctype/stock_ledger/stock_ledger.py | 1 - .../stock_uom_replace_utility/stock_uom_replace_utility.py | 1 - stock/doctype/warehouse/warehouse.py | 1 - support/doctype/customer_issue/customer_issue.py | 1 - support/doctype/maintenance_schedule/maintenance_schedule.py | 1 - support/doctype/maintenance_visit/maintenance_visit.py | 1 - utilities/doctype/sms_control/sms_control.py | 4 +--- 51 files changed, 1 insertion(+), 53 deletions(-) diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py index a6038ddd93..7d8bed9b32 100644 --- a/accounts/doctype/account/account.py +++ b/accounts/doctype/account/account.py @@ -7,7 +7,6 @@ import webnotes from webnotes.utils import flt, fmt_money from webnotes import msgprint, _ -sql = webnotes.conn.sql get_value = webnotes.conn.get_value class DocType: diff --git a/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/accounts/doctype/bank_reconciliation/bank_reconciliation.py index 479b57955c..ce15e57a0e 100644 --- a/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -10,7 +10,6 @@ from webnotes.model.doc import addchild from webnotes.model.bean import getlist, copy_doclist from webnotes import msgprint -sql = webnotes.conn.sql diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 9c1cf3fa67..aa0f11b178 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -8,7 +8,6 @@ from webnotes.utils import flt, fmt_money, getdate from webnotes.model.code import get_obj from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self,d,dl): diff --git a/accounts/doctype/mis_control/mis_control.py b/accounts/doctype/mis_control/mis_control.py index 84350dcb72..bb58270490 100644 --- a/accounts/doctype/mis_control/mis_control.py +++ b/accounts/doctype/mis_control/mis_control.py @@ -11,7 +11,6 @@ from webnotes import session, msgprint import webnotes.defaults -sql = webnotes.conn.sql from accounts.utils import get_balance_on, get_fiscal_year diff --git a/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/accounts/doctype/period_closing_voucher/period_closing_voucher.py index c214a211c0..9df653ad88 100644 --- a/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -11,7 +11,6 @@ from webnotes.model.bean import copy_doclist from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 0538323561..0c5a277a0c 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -12,7 +12,6 @@ from setup.utils import get_company_currency import webnotes.defaults -sql = webnotes.conn.sql from controllers.buying_controller import BuyingController class DocType(BuyingController): diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py index a4534aefd6..0a32fb972d 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py @@ -8,7 +8,6 @@ from webnotes.model import db_exists from webnotes.model.bean import copy_doclist from webnotes.model.code import get_obj -sql = webnotes.conn.sql diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py index 9b6dc6c9ab..dfe2af57f5 100644 --- a/buying/doctype/purchase_common/purchase_common.py +++ b/buying/doctype/purchase_common/purchase_common.py @@ -10,7 +10,6 @@ from webnotes import msgprint, _ from buying.utils import get_last_purchase_details -sql = webnotes.conn.sql from controllers.buying_controller import BuyingController class DocType(BuyingController): diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py index 367517719c..951ff8b70e 100644 --- a/buying/doctype/purchase_order/purchase_order.py +++ b/buying/doctype/purchase_order/purchase_order.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql from controllers.buying_controller import BuyingController class DocType(BuyingController): diff --git a/buying/doctype/supplier/supplier.py b/buying/doctype/supplier/supplier.py index 15e1d625f9..2c1d173ea7 100644 --- a/buying/doctype/supplier/supplier.py +++ b/buying/doctype/supplier/supplier.py @@ -9,7 +9,6 @@ from webnotes.utils import cint from webnotes import msgprint, _ from webnotes.model.doc import make_autoname -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/home/doctype/feed/feed.py b/home/doctype/feed/feed.py index 25abf5798a..ebee5c4ce7 100644 --- a/home/doctype/feed/feed.py +++ b/home/doctype/feed/feed.py @@ -7,7 +7,6 @@ import webnotes from webnotes.model import db_exists from webnotes.model.bean import copy_doclist -sql = webnotes.conn.sql diff --git a/hr/doctype/attendance/attendance.py b/hr/doctype/attendance/attendance.py index 7b82bc524b..124d3621a5 100644 --- a/hr/doctype/attendance/attendance.py +++ b/hr/doctype/attendance/attendance.py @@ -7,7 +7,6 @@ import webnotes from webnotes.utils import getdate, nowdate from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist=[]): diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index e28e02d81b..e8396eb539 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -8,7 +8,6 @@ from webnotes.utils import getdate, validate_email_add, cstr from webnotes.model.doc import make_autoname from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self,doc,doclist=[]): diff --git a/hr/doctype/holiday_list/holiday_list.py b/hr/doctype/holiday_list/holiday_list.py index 81d18f336e..100c1403fa 100644 --- a/hr/doctype/holiday_list/holiday_list.py +++ b/hr/doctype/holiday_list/holiday_list.py @@ -10,7 +10,6 @@ from webnotes.model.doc import addchild, make_autoname from webnotes.model.bean import copy_doclist from webnotes import msgprint -sql = webnotes.conn.sql import datetime diff --git a/hr/doctype/leave_allocation/leave_allocation.py b/hr/doctype/leave_allocation/leave_allocation.py index 1c856fa335..8e226908d8 100755 --- a/hr/doctype/leave_allocation/leave_allocation.py +++ b/hr/doctype/leave_allocation/leave_allocation.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cint, flt from webnotes import msgprint -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist): diff --git a/hr/doctype/leave_control_panel/leave_control_panel.py b/hr/doctype/leave_control_panel/leave_control_panel.py index 30b52ba889..640432109f 100644 --- a/hr/doctype/leave_control_panel/leave_control_panel.py +++ b/hr/doctype/leave_control_panel/leave_control_panel.py @@ -9,7 +9,6 @@ from webnotes.model.doc import Document from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql diff --git a/hr/doctype/salary_manager/salary_manager.py b/hr/doctype/salary_manager/salary_manager.py index 0eadca14c4..ecc829f87a 100644 --- a/hr/doctype/salary_manager/salary_manager.py +++ b/hr/doctype/salary_manager/salary_manager.py @@ -11,7 +11,6 @@ from webnotes.model.bean import getlist, copy_doclist from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql diff --git a/hr/doctype/salary_slip/salary_slip.py b/hr/doctype/salary_slip/salary_slip.py index 36d7ceba84..7104273170 100644 --- a/hr/doctype/salary_slip/salary_slip.py +++ b/hr/doctype/salary_slip/salary_slip.py @@ -11,7 +11,6 @@ from webnotes.model.code import get_obj from webnotes import msgprint, _ from setup.utils import get_company_currency -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/hr/doctype/salary_structure/salary_structure.py b/hr/doctype/salary_structure/salary_structure.py index 50b0160d9a..c3cd93d48c 100644 --- a/hr/doctype/salary_structure/salary_structure.py +++ b/hr/doctype/salary_structure/salary_structure.py @@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt from webnotes.model.doc import addchild, make_autoname from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self,doc,doclist=[]): diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 9a566123c7..84a3d6c13b 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 6a133e78fa..28adc65e36 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt, nowdate from webnotes.model.code import get_obj from webnotes import msgprint, _ -sql = webnotes.conn.sql class OverProductionError(webnotes.ValidationError): pass diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 766f2ac233..c150be3ff6 100644 --- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist=[]): diff --git a/manufacturing/doctype/workstation/workstation.py b/manufacturing/doctype/workstation/workstation.py index 35e2c1f06b..56833a9e5b 100644 --- a/manufacturing/doctype/workstation/workstation.py +++ b/manufacturing/doctype/workstation/workstation.py @@ -8,7 +8,6 @@ from webnotes.utils import flt from webnotes.model import db_exists from webnotes.model.bean import copy_doclist -sql = webnotes.conn.sql diff --git a/projects/doctype/task/task.py b/projects/doctype/task/task.py index 6cd1ba8636..856be5cc88 100644 --- a/projects/doctype/task/task.py +++ b/projects/doctype/task/task.py @@ -9,7 +9,6 @@ from webnotes.model import db_exists from webnotes.model.bean import copy_doclist from webnotes import msgprint -sql = webnotes.conn.sql class DocType: def __init__(self,doc,doclist=[]): diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py index d3a263fbb9..0c2bf616dd 100644 --- a/selling/doctype/customer/customer.py +++ b/selling/doctype/customer/customer.py @@ -9,7 +9,6 @@ from webnotes.model.doc import Document, make_autoname from webnotes import msgprint, _ import webnotes.defaults -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index da11410f24..c0ef242baa 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -7,7 +7,6 @@ from webnotes import _ from webnotes.utils import cstr, validate_email_add, cint, extract_email_id from webnotes import session, msgprint -sql = webnotes.conn.sql from controllers.selling_controller import SellingController diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index b265356a4d..df6861a773 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -8,7 +8,6 @@ from webnotes.utils import cstr, getdate, cint from webnotes.model.bean import getlist from webnotes import msgprint -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 44a67fa45c..8ac0d1925a 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint -sql = webnotes.conn.sql from controllers.selling_controller import SellingController diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 37314845ad..5043a77d76 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -11,7 +11,6 @@ from webnotes.model.code import get_obj from webnotes import msgprint from webnotes.model.mapper import get_mapped_doclist -sql = webnotes.conn.sql from controllers.selling_controller import SellingController diff --git a/selling/doctype/sms_center/sms_center.py b/selling/doctype/sms_center/sms_center.py index c3b5ac0371..8db20b0275 100644 --- a/selling/doctype/sms_center/sms_center.py +++ b/selling/doctype/sms_center/sms_center.py @@ -10,7 +10,6 @@ from webnotes.model.bean import copy_doclist from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql # ---------- diff --git a/setup/doctype/authorization_control/authorization_control.py b/setup/doctype/authorization_control/authorization_control.py index ddf0791bde..26f7705af3 100644 --- a/setup/doctype/authorization_control/authorization_control.py +++ b/setup/doctype/authorization_control/authorization_control.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes import session, msgprint from setup.utils import get_company_currency -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/setup/doctype/authorization_rule/authorization_rule.py b/setup/doctype/authorization_rule/authorization_rule.py index 3d2de4776d..5192ebf769 100644 --- a/setup/doctype/authorization_rule/authorization_rule.py +++ b/setup/doctype/authorization_rule/authorization_rule.py @@ -9,7 +9,6 @@ from webnotes.model import db_exists from webnotes.model.bean import copy_doclist from webnotes import msgprint -sql = webnotes.conn.sql diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index eeff2d1bef..bb0ee1baeb 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -10,7 +10,6 @@ from webnotes.model.doc import Document from webnotes.model.code import get_obj import webnotes.defaults -sql = webnotes.conn.sql class DocType: def __init__(self,d,dl): diff --git a/setup/doctype/customer_group/customer_group.py b/setup/doctype/customer_group/customer_group.py index 0940e1f0b3..8b68cc50e4 100644 --- a/setup/doctype/customer_group/customer_group.py +++ b/setup/doctype/customer_group/customer_group.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint -sql = webnotes.conn.sql from webnotes.utils.nestedset import DocTypeNestedSet class DocType(DocTypeNestedSet): diff --git a/setup/doctype/email_settings/email_settings.py b/setup/doctype/email_settings/email_settings.py index 219501eb13..aa511eefcd 100644 --- a/setup/doctype/email_settings/email_settings.py +++ b/setup/doctype/email_settings/email_settings.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import webnotes -sql = webnotes.conn.sql from webnotes.utils import cint diff --git a/setup/doctype/naming_series/naming_series.py b/setup/doctype/naming_series/naming_series.py index 9cc4de294b..6312801fe8 100644 --- a/setup/doctype/naming_series/naming_series.py +++ b/setup/doctype/naming_series/naming_series.py @@ -8,7 +8,6 @@ from webnotes.utils import cstr from webnotes import msgprint import webnotes.model.doctype -sql = webnotes.conn.sql class DocType: def __init__(self, d, dl): diff --git a/setup/doctype/notification_control/notification_control.py b/setup/doctype/notification_control/notification_control.py index 6133d9b701..23493624dd 100644 --- a/setup/doctype/notification_control/notification_control.py +++ b/setup/doctype/notification_control/notification_control.py @@ -6,7 +6,6 @@ import webnotes from webnotes import msgprint -sql = webnotes.conn.sql class DocType: def __init__(self,d,dl): diff --git a/setup/doctype/print_heading/print_heading.py b/setup/doctype/print_heading/print_heading.py index ba7114a22d..134aaaf013 100644 --- a/setup/doctype/print_heading/print_heading.py +++ b/setup/doctype/print_heading/print_heading.py @@ -7,7 +7,6 @@ import webnotes from webnotes.model import db_exists from webnotes.model.bean import copy_doclist -sql = webnotes.conn.sql diff --git a/setup/doctype/sales_partner/sales_partner.py b/setup/doctype/sales_partner/sales_partner.py index 0d7e12d999..8915ff1cc0 100644 --- a/setup/doctype/sales_partner/sales_partner.py +++ b/setup/doctype/sales_partner/sales_partner.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cint, cstr, filter_strip_join -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist=None): diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 146191f9b1..954ef783a4 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate from webnotes import msgprint, _ -sql = webnotes.conn.sql import webnotes.defaults diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 042b197f13..ce06ce3d0b 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -13,7 +13,6 @@ from webnotes.model.mapper import get_mapped_doclist -sql = webnotes.conn.sql from controllers.selling_controller import SellingController diff --git a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py index 0cdad4d949..5275632054 100644 --- a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py +++ b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py @@ -9,7 +9,6 @@ from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql class DocType: diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index f7cfcff093..084f30cd59 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -10,7 +10,6 @@ from webnotes.model.code import get_obj from webnotes import msgprint import webnotes.defaults -sql = webnotes.conn.sql from controllers.buying_controller import BuyingController class DocType(BuyingController): diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 6a61461ac5..b5e1edf09c 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -15,7 +15,6 @@ from stock.stock_ledger import get_previous_sle from controllers.queries import get_match_cond import json -sql = webnotes.conn.sql class NotUpdateStockError(webnotes.ValidationError): pass class StockOverReturnError(webnotes.ValidationError): pass diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py index 10fb7617f0..1624b007d3 100644 --- a/stock/doctype/stock_ledger/stock_ledger.py +++ b/stock/doctype/stock_ledger/stock_ledger.py @@ -11,7 +11,6 @@ from webnotes.model.code import get_obj from webnotes import session, msgprint from stock.utils import get_valid_serial_nos -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist=[]): diff --git a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py index 321e3c9807..2ec9debf7f 100644 --- a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py +++ b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py @@ -10,7 +10,6 @@ from webnotes.model.bean import copy_doclist from webnotes.model.code import get_obj from webnotes import msgprint, _ -sql = webnotes.conn.sql class DocType: def __init__(self, d, dl=[]): diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index 0de27fe647..b23f043a3d 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -8,7 +8,6 @@ from webnotes.utils import flt, validate_email_add from webnotes.model.code import get_obj from webnotes import msgprint -sql = webnotes.conn.sql class DocType: def __init__(self, doc, doclist=[]): diff --git a/support/doctype/customer_issue/customer_issue.py b/support/doctype/customer_issue/customer_issue.py index 910e9b845d..3773cdf360 100644 --- a/support/doctype/customer_issue/customer_issue.py +++ b/support/doctype/customer_issue/customer_issue.py @@ -7,7 +7,6 @@ import webnotes from webnotes import session, msgprint from webnotes.utils import today -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/support/doctype/maintenance_schedule/maintenance_schedule.py b/support/doctype/maintenance_schedule/maintenance_schedule.py index 59d3f8eb38..4bb121767c 100644 --- a/support/doctype/maintenance_schedule/maintenance_schedule.py +++ b/support/doctype/maintenance_schedule/maintenance_schedule.py @@ -9,7 +9,6 @@ from webnotes.model.doc import addchild from webnotes.model.bean import getlist from webnotes import msgprint -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase, delete_events diff --git a/support/doctype/maintenance_visit/maintenance_visit.py b/support/doctype/maintenance_visit/maintenance_visit.py index bf8767bece..dbb2880ac9 100644 --- a/support/doctype/maintenance_visit/maintenance_visit.py +++ b/support/doctype/maintenance_visit/maintenance_visit.py @@ -8,7 +8,6 @@ from webnotes.utils import cstr from webnotes.model.bean import getlist from webnotes import msgprint -sql = webnotes.conn.sql from utilities.transaction_base import TransactionBase diff --git a/utilities/doctype/sms_control/sms_control.py b/utilities/doctype/sms_control/sms_control.py index 9c2319fcfb..d72db529dd 100644 --- a/utilities/doctype/sms_control/sms_control.py +++ b/utilities/doctype/sms_control/sms_control.py @@ -10,8 +10,6 @@ from webnotes.model.doc import Document from webnotes import msgprint from webnotes.model.bean import getlist, copy_doclist -sql = webnotes.conn.sql - class DocType: def __init__(self, doc, doclist=[]): self.doc = doc @@ -119,4 +117,4 @@ class DocType: sl.message = arg['message'] sl.no_of_requested_sms = len(arg['receiver_list']) sl.no_of_sent_sms = sent_sms - sl.save(new=1) \ No newline at end of file + sl.save(new=1) From 5e16a69b35fc76d8412ce332bb5eeed387af0c5d Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 18 Sep 2013 12:20:53 +0530 Subject: [PATCH 004/123] mass replace sql with webnotes.conn.sql --- accounts/doctype/account/account.py | 14 ++++---- .../bank_reconciliation.py | 4 +-- accounts/doctype/gl_entry/gl_entry.py | 8 ++--- accounts/doctype/mis_control/mis_control.py | 12 +++---- .../period_closing_voucher.py | 16 +++++----- .../purchase_invoice/purchase_invoice.py | 18 +++++------ .../purchase_common/purchase_common.py | 28 ++++++++-------- .../doctype/purchase_order/purchase_order.py | 6 ++-- buying/doctype/supplier/supplier.py | 20 ++++++------ hr/doctype/attendance/attendance.py | 6 ++-- .../leave_allocation/leave_allocation.py | 10 +++--- .../leave_control_panel.py | 2 +- hr/doctype/salary_manager/salary_manager.py | 12 +++---- .../salary_manager/test_salary_manager.py | 14 ++++---- hr/doctype/salary_slip/salary_slip.py | 14 ++++---- .../salary_structure/salary_structure.py | 8 ++--- manufacturing/doctype/bom/bom.py | 18 +++++------ .../production_order/production_order.py | 6 ++-- .../production_planning_tool.py | 20 ++++++------ .../doctype/workstation/workstation.py | 4 +-- projects/doctype/task/task.py | 4 +-- selling/doctype/customer/customer.py | 8 ++--- selling/doctype/lead/lead.py | 2 +- selling/doctype/opportunity/opportunity.py | 12 +++---- selling/doctype/quotation/quotation.py | 14 ++++---- selling/doctype/sales_order/sales_order.py | 32 +++++++++---------- selling/doctype/sms_center/sms_center.py | 8 ++--- .../authorization_control.py | 30 ++++++++--------- .../authorization_rule/authorization_rule.py | 8 ++--- .../doctype/customer_group/customer_group.py | 6 ++-- setup/doctype/naming_series/naming_series.py | 6 ++-- .../notification_control.py | 2 +- setup/doctype/sales_partner/sales_partner.py | 2 +- stock/doctype/bin/bin.py | 2 +- stock/doctype/delivery_note/delivery_note.py | 12 +++---- .../landed_cost_wizard/landed_cost_wizard.py | 14 ++++---- .../purchase_receipt/purchase_receipt.py | 8 ++--- stock/doctype/stock_entry/stock_entry.py | 14 ++++---- .../stock_uom_replace_utility.py | 12 +++---- stock/doctype/warehouse/warehouse.py | 10 +++--- .../doctype/customer_issue/customer_issue.py | 2 +- .../maintenance_schedule.py | 16 +++++----- .../maintenance_visit/maintenance_visit.py | 10 +++--- utilities/doctype/contact/contact.py | 15 ++++----- utilities/doctype/sms_control/sms_control.py | 2 +- 45 files changed, 245 insertions(+), 246 deletions(-) diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py index 7d8bed9b32..65274d7ba9 100644 --- a/accounts/doctype/account/account.py +++ b/accounts/doctype/account/account.py @@ -32,7 +32,7 @@ class DocType: def validate_parent(self): """Fetch Parent Details and validation for account not to be created under ledger""" if self.doc.parent_account: - par = sql("""select name, group_or_ledger, is_pl_account, debit_or_credit + par = webnotes.conn.sql("""select name, group_or_ledger, is_pl_account, debit_or_credit from tabAccount where name =%s""", self.doc.parent_account) if not par: msgprint("Parent account does not exists", raise_exception=1) @@ -60,7 +60,7 @@ class DocType: def validate_duplicate_account(self): if self.doc.fields.get('__islocal') or not self.doc.name: company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - if sql("""select name from tabAccount where name=%s""", + if webnotes.conn.sql("""select name from tabAccount where name=%s""", (self.doc.account_name + " - " + company_abbr)): msgprint("Account Name: %s already exists, please rename" % self.doc.account_name, raise_exception=1) @@ -97,12 +97,12 @@ class DocType: # Check if any previous balance exists def check_gle_exists(self): - exists = sql("""select name from `tabGL Entry` where account = %s + exists = webnotes.conn.sql("""select name from `tabGL Entry` where account = %s and ifnull(is_cancelled, 'No') = 'No'""", self.doc.name) return exists and exists[0][0] or '' def check_if_child_exists(self): - return sql("""select name from `tabAccount` where parent_account = %s + return webnotes.conn.sql("""select name from `tabAccount` where parent_account = %s and docstatus != 2""", self.doc.name) def validate_mandatory(self): @@ -141,7 +141,7 @@ class DocType: # Get credit limit credit_limit_from = 'Customer' - cr_limit = sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2 + cr_limit = webnotes.conn.sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2 where t2.name=%s and t1.name = t2.master_name""", account) credit_limit = cr_limit and flt(cr_limit[0][0]) or 0 if not credit_limit: @@ -173,7 +173,7 @@ class DocType: self.update_nsm_model() # delete all cancelled gl entry of this account - sql("""delete from `tabGL Entry` where account = %s and + webnotes.conn.sql("""delete from `tabGL Entry` where account = %s and ifnull(is_cancelled, 'No') = 'Yes'""", self.doc.name) def on_rename(self, new, old, merge=False): @@ -185,7 +185,7 @@ class DocType: # rename account name new_account_name = " - ".join(parts[:-1]) - sql("update `tabAccount` set account_name = %s where name = %s", (new_account_name, old)) + webnotes.conn.sql("update `tabAccount` set account_name = %s where name = %s", (new_account_name, old)) if merge: new_name = " - ".join(parts) diff --git a/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/accounts/doctype/bank_reconciliation/bank_reconciliation.py index ce15e57a0e..132358ef83 100644 --- a/accounts/doctype/bank_reconciliation/bank_reconciliation.py +++ b/accounts/doctype/bank_reconciliation/bank_reconciliation.py @@ -22,7 +22,7 @@ class DocType: msgprint("Bank Account, From Date and To Date are Mandatory") return - dl = sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.doc.bank_account, self.doc.from_date, self.doc.to_date)) + dl = webnotes.conn.sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.doc.bank_account, self.doc.from_date, self.doc.to_date)) self.doclist = self.doc.clear_table(self.doclist, 'entries') self.doc.total_amount = 0.0 @@ -46,7 +46,7 @@ class DocType: msgprint("Clearance Date can not be before Cheque Date (Row #%s)" % d.idx, raise_exception=1) - sql("""update `tabJournal Voucher` + webnotes.conn.sql("""update `tabJournal Voucher` set clearance_date = %s, modified = %s where name=%s""", (d.clearance_date, nowdate(), d.voucher_id)) vouchers.append(d.voucher_id) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index aa0f11b178..5cde97a706 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -63,7 +63,7 @@ class DocType: tot_outstanding = 0 #needed when there is no GL Entry in the system for that acc head if (self.doc.voucher_type=='Journal Voucher' or self.doc.voucher_type=='Sales Invoice') \ and (master_type =='Customer' and master_name): - dbcr = sql("""select sum(debit), sum(credit) from `tabGL Entry` + dbcr = webnotes.conn.sql("""select sum(debit), sum(credit) from `tabGL Entry` where account = '%s' and is_cancelled='No'""" % self.doc.account) if dbcr: tot_outstanding = flt(dbcr[0][0]) - flt(dbcr[0][1]) + \ @@ -80,7 +80,7 @@ class DocType: def validate_account_details(self, adv_adj): """Account must be ledger, active and not freezed""" - ret = sql("""select group_or_ledger, docstatus, freeze_account, company + ret = webnotes.conn.sql("""select group_or_ledger, docstatus, freeze_account, company from tabAccount where name=%s""", self.doc.account, as_dict=1) if ret and ret[0]["group_or_ledger"]=='Group': @@ -145,7 +145,7 @@ class DocType: def update_outstanding_amt(self): # get final outstanding amt - bal = flt(sql("""select sum(debit) - sum(credit) from `tabGL Entry` + bal = flt(webnotes.conn.sql("""select sum(debit) - sum(credit) from `tabGL Entry` where against_voucher=%s and against_voucher_type=%s and account = %s and ifnull(is_cancelled,'No') = 'No'""", (self.doc.against_voucher, self.doc.against_voucher_type, self.doc.account))[0][0] or 0.0) @@ -170,5 +170,5 @@ class DocType: # Update outstanding amt on against voucher if self.doc.against_voucher_type in ["Sales Invoice", "Purchase Invoice"]: - sql("update `tab%s` set outstanding_amount=%s where name='%s'"% + webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'"% (self.doc.against_voucher_type, bal, self.doc.against_voucher)) \ No newline at end of file diff --git a/accounts/doctype/mis_control/mis_control.py b/accounts/doctype/mis_control/mis_control.py index bb58270490..f10e3d7df3 100644 --- a/accounts/doctype/mis_control/mis_control.py +++ b/accounts/doctype/mis_control/mis_control.py @@ -43,7 +43,7 @@ class DocType: ret['company'] = get_companies() #--- to get fiscal year and start_date of that fiscal year ----- - res = sql("select name, year_start_date from `tabFiscal Year`") + res = webnotes.conn.sql("select name, year_start_date from `tabFiscal Year`") ret['fiscal_year'] = [r[0] for r in res] ret['start_dates'] = {} for r in res: @@ -51,7 +51,7 @@ class DocType: #--- from month and to month (for MIS - Comparison Report) ------- month_list = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] - fiscal_start_month = sql("select MONTH(year_start_date) from `tabFiscal Year` where name = %s",(webnotes.defaults.get_global_default("fiscal_year"))) + fiscal_start_month = webnotes.conn.sql("select MONTH(year_start_date) from `tabFiscal Year` where name = %s",(webnotes.defaults.get_global_default("fiscal_year"))) fiscal_start_month = fiscal_start_month and fiscal_start_month[0][0] or 1 mon = [''] for i in range(fiscal_start_month,13): mon.append(month_list[i-1]) @@ -106,7 +106,7 @@ class DocType: def dates(self,fiscal_year,from_date,to_date): import datetime ret = '' - start_date = cstr(sql("select year_start_date from `tabFiscal Year` where name = %s",fiscal_year)[0][0]) + start_date = cstr(webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name = %s",fiscal_year)[0][0]) st_mon = cint(from_date.split('-')[1]) ed_mon = cint(to_date.split('-')[1]) st_day = cint(from_date.split('-')[2]) @@ -151,7 +151,7 @@ class DocType: def get_totals(self, args): args = eval(args) #msgprint(args) - totals = sql("SELECT %s FROM %s WHERE %s %s %s %s" %(cstr(args['query_val']), cstr(args['tables']), cstr(args['company']), cstr(args['cond']), cstr(args['add_cond']), cstr(args['fil_cond'])), as_dict = 1)[0] + totals = webnotes.conn.sql("SELECT %s FROM %s WHERE %s %s %s %s" %(cstr(args['query_val']), cstr(args['tables']), cstr(args['company']), cstr(args['cond']), cstr(args['add_cond']), cstr(args['fil_cond'])), as_dict = 1)[0] #msgprint(totals) tot_keys = totals.keys() # return in flt because JSON doesn't accept Decimal @@ -184,7 +184,7 @@ class DocType: # Get Children # ------------ def get_children(self, parent_account, level, pl, company, fy): - cl = sql("select distinct account_name, name, debit_or_credit, lft, rgt from `tabAccount` where ifnull(parent_account, '') = %s and ifnull(is_pl_account, 'No')=%s and company=%s and docstatus != 2 order by name asc", (parent_account, pl, company)) + cl = webnotes.conn.sql("select distinct account_name, name, debit_or_credit, lft, rgt from `tabAccount` where ifnull(parent_account, '') = %s and ifnull(is_pl_account, 'No')=%s and company=%s and docstatus != 2 order by name asc", (parent_account, pl, company)) level0_diff = [0 for p in self.period_list] if pl=='Yes' and level==0: # switch for income & expenses cl = [c for c in cl] @@ -237,7 +237,7 @@ class DocType: def define_periods(self, year, period): # get year start date - ysd = sql("select year_start_date from `tabFiscal Year` where name=%s", year) + ysd = webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name=%s", year) ysd = ysd and ysd[0][0] or '' self.ysd = ysd diff --git a/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 9df653ad88..237bb638a5 100644 --- a/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -23,7 +23,7 @@ class DocType: def validate_account_head(self): - acc_det = sql("select debit_or_credit, is_pl_account, group_or_ledger, company \ + acc_det = webnotes.conn.sql("select debit_or_credit, is_pl_account, group_or_ledger, company \ from `tabAccount` where name = '%s'" % (self.doc.closing_account_head)) # Account should be under liability @@ -43,7 +43,7 @@ class DocType: def validate_posting_date(self): - yr = sql("""select year_start_date, adddate(year_start_date, interval 1 year) + yr = webnotes.conn.sql("""select year_start_date, adddate(year_start_date, interval 1 year) from `tabFiscal Year` where name=%s""", (self.doc.fiscal_year, )) self.year_start_date = yr and yr[0][0] or '' self.year_end_date = yr and yr[0][1] or '' @@ -54,7 +54,7 @@ class DocType: raise Exception # Period Closing Entry - pce = sql("select name from `tabPeriod Closing Voucher` \ + pce = webnotes.conn.sql("select name from `tabPeriod Closing Voucher` \ where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" \ % (self.doc.posting_date, self.doc.fiscal_year)) if pce and pce[0][0]: @@ -64,13 +64,13 @@ class DocType: def validate_pl_balances(self): - income_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + income_bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \ and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' \ and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \ and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) - expense_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + expense_bal = webnotes.conn.sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \ and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' \ and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \ @@ -86,7 +86,7 @@ class DocType: def get_pl_balances(self, d_or_c): """Get account (pl) specific balance""" - acc_bal = sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + acc_bal = webnotes.conn.sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' \ and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' \ and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' \ @@ -169,7 +169,7 @@ class DocType: def on_cancel(self): # get all submit entries of current closing entry voucher - gl_entries = sql("select account, debit, credit from `tabGL Entry` where voucher_type = 'Period Closing Voucher' and voucher_no = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (self.doc.name)) + gl_entries = webnotes.conn.sql("select account, debit, credit from `tabGL Entry` where voucher_type = 'Period Closing Voucher' and voucher_no = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (self.doc.name)) # Swap Debit & Credit Column and make gl entry for gl in gl_entries: @@ -177,4 +177,4 @@ class DocType: self.save_entry(fdict, is_cancel = 'Yes') # Update is_cancelled = 'Yes' to all gl entries for current voucher - sql("update `tabGL Entry` set is_cancelled = 'Yes' where voucher_type = '%s' and voucher_no = '%s'" % (self.doc.doctype, self.doc.name)) \ No newline at end of file + webnotes.conn.sql("update `tabGL Entry` set is_cancelled = 'Yes' where voucher_type = '%s' and voucher_no = '%s'" % (self.doc.doctype, self.doc.name)) \ No newline at end of file diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 0c5a277a0c..be0e224128 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -61,7 +61,7 @@ class DocType(BuyingController): "purchase_receipt_details") def get_credit_to(self): - acc_head = sql("""select name, credit_days from `tabAccount` + acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount` where (name = %s or (master_name = %s and master_type = 'supplier')) and docstatus != 2 and company = %s""", (cstr(self.doc.supplier) + " - " + self.company_abbr, @@ -88,14 +88,14 @@ class DocType(BuyingController): return get_obj('Purchase Common').get_rate(arg,self) def get_rate1(self,acc): - rate = sql("select tax_rate from `tabAccount` where name='%s'"%(acc)) + rate = webnotes.conn.sql("select tax_rate from `tabAccount` where name='%s'"%(acc)) ret={'add_tax_rate' :rate and flt(rate[0][0]) or 0 } return ret def check_active_purchase_items(self): for d in getlist(self.doclist, 'entries'): if d.item_code: # extra condn coz item_code is not mandatory in PV - valid_item = sql("select docstatus,is_purchase_item from tabItem where name = %s",d.item_code) + valid_item = webnotes.conn.sql("select docstatus,is_purchase_item from tabItem where name = %s",d.item_code) if valid_item[0][0] == 2: msgprint("Item : '%s' is Inactive, you can restore it from Trash" %(d.item_code)) raise Exception @@ -115,7 +115,7 @@ class DocType(BuyingController): def validate_bill_no(self): if self.doc.bill_no and self.doc.bill_no.lower().strip() \ not in ['na', 'not applicable', 'none']: - b_no = sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice` + b_no = webnotes.conn.sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice` where bill_no = %s and credit_to = %s and docstatus = 1 and name != %s""", (self.doc.bill_no, self.doc.credit_to, self.doc.name)) if b_no and cstr(b_no[0][2]) == cstr(self.doc.is_opening): @@ -131,7 +131,7 @@ class DocType(BuyingController): self.doc.remarks = "No Remarks" def validate_credit_acc(self): - acc = sql("select debit_or_credit, is_pl_account from tabAccount where name = %s", + acc = webnotes.conn.sql("select debit_or_credit, is_pl_account from tabAccount where name = %s", self.doc.credit_to) if not acc: msgprint("Account: "+ self.doc.credit_to + "does not exist") @@ -147,7 +147,7 @@ class DocType(BuyingController): # ------------------------------------------------------------ def check_for_acc_head_of_supplier(self): if self.doc.supplier and self.doc.credit_to: - acc_head = sql("select master_name from `tabAccount` where name = %s", self.doc.credit_to) + acc_head = webnotes.conn.sql("select master_name from `tabAccount` where name = %s", self.doc.credit_to) if (acc_head and cstr(acc_head[0][0]) != cstr(self.doc.supplier)) or (not acc_head and (self.doc.credit_to != cstr(self.doc.supplier) + " - " + self.company_abbr)): msgprint("Credit To: %s do not match with Supplier: %s for Company: %s.\n If both correctly entered, please select Master Type and Master Name in account master." %(self.doc.credit_to,self.doc.supplier,self.doc.company), raise_exception=1) @@ -159,7 +159,7 @@ class DocType(BuyingController): for d in getlist(self.doclist,'entries'): if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt: check_list.append(d.purhcase_order) - stopped = sql("select name from `tabPurchase Order` where status = 'Stopped' and name = '%s'" % d.purchase_order) + stopped = webnotes.conn.sql("select name from `tabPurchase Order` where status = 'Stopped' and name = '%s'" % d.purchase_order) if stopped: msgprint("One cannot do any transaction against 'Purchase Order' : %s, it's status is 'Stopped'" % (d.purhcase_order)) raise Exception @@ -258,11 +258,11 @@ class DocType(BuyingController): def check_prev_docstatus(self): for d in getlist(self.doclist,'entries'): if d.purchase_order: - submitted = sql("select name from `tabPurchase Order` where docstatus = 1 and name = '%s'" % d.purchase_order) + submitted = webnotes.conn.sql("select name from `tabPurchase Order` where docstatus = 1 and name = '%s'" % d.purchase_order) if not submitted: webnotes.throw("Purchase Order : "+ cstr(d.purchase_order) +" is not submitted") if d.purchase_receipt: - submitted = sql("select name from `tabPurchase Receipt` where docstatus = 1 and name = '%s'" % d.purchase_receipt) + submitted = webnotes.conn.sql("select name from `tabPurchase Receipt` where docstatus = 1 and name = '%s'" % d.purchase_receipt) if not submitted: webnotes.throw("Purchase Receipt : "+ cstr(d.purchase_receipt) +" is not submitted") diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py index dfe2af57f5..c05aba4883 100644 --- a/buying/doctype/purchase_common/purchase_common.py +++ b/buying/doctype/purchase_common/purchase_common.py @@ -22,14 +22,14 @@ class DocType(BuyingController): msgprint(_("You need to put at least one item in the item table."), raise_exception=True) def get_supplier_details(self, name = ''): - details = sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1) + details = webnotes.conn.sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1) if details: ret = { 'supplier_name' : details and details[0]['supplier_name'] or '', 'supplier_address' : details and details[0]['address'] or '' } # ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query) - contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1) + contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1) ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or '' return ret else: @@ -39,7 +39,7 @@ class DocType(BuyingController): # Get Available Qty at Warehouse def get_bin_details( self, arg = ''): arg = eval(arg) - bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (arg['item_code'], arg['warehouse']), as_dict=1) + bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (arg['item_code'], arg['warehouse']), as_dict=1) ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 } return ret @@ -69,7 +69,7 @@ class DocType(BuyingController): # update last purchsae rate if last_purchase_rate: - sql("update `tabItem` set last_purchase_rate = %s where name = %s", + webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s", (flt(last_purchase_rate),d.item_code)) def get_last_purchase_rate(self, obj): @@ -106,7 +106,7 @@ class DocType(BuyingController): raise Exception # udpate with latest quantities - bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) + bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0} if d.doctype == 'Purchase Receipt Item': @@ -115,7 +115,7 @@ class DocType(BuyingController): if d.fields.has_key(x): d.fields[x] = f_lst[x] - item = sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s", + item = webnotes.conn.sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s", d.item_code) if not item: msgprint("Item %s does not exist in Item Master." % cstr(d.item_code), raise_exception=True) @@ -138,7 +138,7 @@ class DocType(BuyingController): # if is not stock item f = [d.schedule_date, d.item_code, d.description] - ch = sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code) + ch = webnotes.conn.sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code) if ch and ch[0][0] == 'Yes': # check for same items @@ -164,18 +164,18 @@ class DocType(BuyingController): # but if in Material Request uom KG it can change in PO get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty' - qty = sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name)) + qty = webnotes.conn.sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name)) qty = qty and flt(qty[0][0]) or 0 # get total qty of ref doctype #-------------------- - max_qty = sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn)) + max_qty = webnotes.conn.sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn)) max_qty = max_qty and flt(max_qty[0][0]) or 0 return cstr(qty)+'~~~'+cstr(max_qty) def check_for_stopped_status(self, doctype, docname): - stopped = sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" % + stopped = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" % ( doctype, docname)) if stopped: msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" % @@ -183,7 +183,7 @@ class DocType(BuyingController): def check_docstatus(self, check, doctype, docname , detail_doctype = ''): if check == 'Next': - submitted = sql("""select t1.name from `tab%s` t1,`tab%s` t2 + submitted = webnotes.conn.sql("""select t1.name from `tab%s` t1,`tab%s` t2 where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1""" % (doctype, detail_doctype, '%s'), docname) if submitted: @@ -191,7 +191,7 @@ class DocType(BuyingController): + _(" has already been submitted."), raise_exception=1) if check == 'Previous': - submitted = sql("""select name from `tab%s` + submitted = webnotes.conn.sql("""select name from `tab%s` where docstatus = 1 and name = %s"""% (doctype, '%s'), docname) if not submitted: msgprint(cstr(doctype) + ": " + cstr(submitted[0][0]) @@ -199,7 +199,7 @@ class DocType(BuyingController): def get_rate(self, arg, obj): arg = eval(arg) - rate = sql("select account_type, tax_rate from `tabAccount` where name = %s" + rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = %s" , (arg['account_head']), as_dict=1) return {'rate': rate and (rate[0]['account_type'] == 'Tax' \ @@ -208,6 +208,6 @@ class DocType(BuyingController): def get_prevdoc_date(self, obj): for d in getlist(obj.doclist, obj.fname): if d.prevdoc_doctype and d.prevdoc_docname: - dt = sql("select transaction_date from `tab%s` where name = %s" + dt = webnotes.conn.sql("select transaction_date from `tab%s` where name = %s" % (d.prevdoc_doctype, '%s'), (d.prevdoc_docname)) d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or '' \ No newline at end of file diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py index 951ff8b70e..c41b9dfef8 100644 --- a/buying/doctype/purchase_order/purchase_order.py +++ b/buying/doctype/purchase_order/purchase_order.py @@ -130,8 +130,8 @@ class DocType(BuyingController): get_obj("Warehouse", d.warehouse).update_bin(args) def check_modified_date(self): - mod_db = sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name) - date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) + mod_db = webnotes.conn.sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name) + date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) if date_diff and date_diff[0][0]: msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ") @@ -170,7 +170,7 @@ class DocType(BuyingController): pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item') # Check if Purchase Invoice has been submitted against current Purchase Order - submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name) + submitted = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name) if submitted: msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !") raise Exception diff --git a/buying/doctype/supplier/supplier.py b/buying/doctype/supplier/supplier.py index 2c1d173ea7..3c0163367b 100644 --- a/buying/doctype/supplier/supplier.py +++ b/buying/doctype/supplier/supplier.py @@ -28,7 +28,7 @@ class DocType(TransactionBase): self.doc.name = make_autoname(self.doc.naming_series + '.#####') def update_credit_days_limit(self): - sql("""update tabAccount set credit_days = %s where name = %s""", + webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""", (cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr())) def on_update(self): @@ -42,7 +42,7 @@ class DocType(TransactionBase): self.update_credit_days_limit() def get_payables_group(self): - g = sql("select payables_group from tabCompany where name=%s", self.doc.company) + g = webnotes.conn.sql("select payables_group from tabCompany where name=%s", self.doc.company) g = g and g[0][0] or '' if not g: msgprint("Update Company master, assign a default group for Payables") @@ -64,14 +64,14 @@ class DocType(TransactionBase): msgprint(_("Created Group ") + ac) def get_company_abbr(self): - return sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] + return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] def get_parent_account(self, abbr): if (not self.doc.supplier_type): msgprint("Supplier Type is mandatory") raise Exception - if not sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)): + if not webnotes.conn.sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)): # if not group created , create it self.add_account(self.doc.supplier_type, self.get_payables_group(), abbr) @@ -89,7 +89,7 @@ class DocType(TransactionBase): abbr = self.get_company_abbr() parent_account = self.get_parent_account(abbr) - if not sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)): + if not webnotes.conn.sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)): ac_bean = webnotes.bean({ "doctype": "Account", 'account_name': self.doc.name, @@ -120,15 +120,15 @@ class DocType(TransactionBase): def get_contacts(self,nm): if nm: - contact_details =webnotes.conn.convert_to_lists(sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm)) + contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm)) return contact_details else: return '' def delete_supplier_address(self): - for rec in sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1): - sql("delete from `tabAddress` where name=%s",(rec['name'])) + for rec in webnotes.conn.sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1): + webnotes.conn.sql("delete from `tabAddress` where name=%s",(rec['name'])) def delete_supplier_contact(self): for contact in webnotes.conn.sql_list("""select name from `tabContact` @@ -137,7 +137,7 @@ class DocType(TransactionBase): def delete_supplier_account(self): """delete supplier's ledger if exist and check balance before deletion""" - acc = sql("select name from `tabAccount` where master_type = 'Supplier' \ + acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Supplier' \ and master_name = %s and docstatus < 2", self.doc.name) if acc: from webnotes.model import delete_doc @@ -160,7 +160,7 @@ class DocType(TransactionBase): ('Purchase Receipt', 'supplier'), ('Serial No', 'supplier')] for rec in update_fields: - sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \ + webnotes.conn.sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \ (rec[0], '%s', rec[1], '%s'), (new, old)) for account in webnotes.conn.sql("""select name, account_name from diff --git a/hr/doctype/attendance/attendance.py b/hr/doctype/attendance/attendance.py index 124d3621a5..6d52b5723d 100644 --- a/hr/doctype/attendance/attendance.py +++ b/hr/doctype/attendance/attendance.py @@ -14,7 +14,7 @@ class DocType: self.doclist = doclist def validate_duplicate_record(self): - res = sql("""select name from `tabAttendance` where employee = %s and att_date = %s + res = webnotes.conn.sql("""select name from `tabAttendance` where employee = %s and att_date = %s and name != %s and docstatus = 1""", (self.doc.employee, self.doc.att_date, self.doc.name)) if res: @@ -23,7 +23,7 @@ class DocType: def check_leave_record(self): if self.doc.status == 'Present': - leave = sql("""select name from `tabLeave Application` + leave = webnotes.conn.sql("""select name from `tabLeave Application` where employee = %s and %s between from_date and to_date and status = 'Approved' and docstatus = 1""", (self.doc.employee, self.doc.att_date)) @@ -41,7 +41,7 @@ class DocType: msgprint(_("Attendance can not be marked for future dates"), raise_exception=1) def validate_employee(self): - emp = sql("select name from `tabEmployee` where name = %s and status = 'Active'", + emp = webnotes.conn.sql("select name from `tabEmployee` where name = %s and status = 'Active'", self.doc.employee) if not emp: msgprint(_("Employee: ") + self.doc.employee + diff --git a/hr/doctype/leave_allocation/leave_allocation.py b/hr/doctype/leave_allocation/leave_allocation.py index 8e226908d8..a058e1db77 100755 --- a/hr/doctype/leave_allocation/leave_allocation.py +++ b/hr/doctype/leave_allocation/leave_allocation.py @@ -36,7 +36,7 @@ class DocType: def check_existing_leave_allocation(self): """check whether leave for same type is already allocated or not""" - leave_allocation = sql("""select name from `tabLeave Allocation` + leave_allocation = webnotes.conn.sql("""select name from `tabLeave Allocation` where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""", (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year)) if leave_allocation: @@ -63,14 +63,14 @@ class DocType: return self.get_leaves_allocated(prev_fyear) - self.get_leaves_applied(prev_fyear) def get_leaves_applied(self, fiscal_year): - leaves_applied = sql("""select SUM(ifnull(total_leave_days, 0)) + leaves_applied = webnotes.conn.sql("""select SUM(ifnull(total_leave_days, 0)) from `tabLeave Application` where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""", (self.doc.employee, self.doc.leave_type, fiscal_year)) return leaves_applied and flt(leaves_applied[0][0]) or 0 def get_leaves_allocated(self, fiscal_year): - leaves_allocated = sql("""select SUM(ifnull(total_leaves_allocated, 0)) + leaves_allocated = webnotes.conn.sql("""select SUM(ifnull(total_leaves_allocated, 0)) from `tabLeave Allocation` where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1 and name!=%s""", (self.doc.employee, self.doc.leave_type, fiscal_year, self.doc.name)) @@ -78,7 +78,7 @@ class DocType: def allow_carry_forward(self): """check whether carry forward is allowed or not for this leave type""" - cf = sql("""select is_carry_forward from `tabLeave Type` where name = %s""", + cf = webnotes.conn.sql("""select is_carry_forward from `tabLeave Type` where name = %s""", self.doc.leave_type) cf = cf and cint(cf[0][0]) or 0 if not cf: @@ -109,7 +109,7 @@ class DocType: webnotes.conn.set(self.doc,'total_leaves_allocated',flt(leave_det['total_leaves_allocated'])) def check_for_leave_application(self): - exists = sql("""select name from `tabLeave Application` + exists = webnotes.conn.sql("""select name from `tabLeave Application` where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""", (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year)) if exists: diff --git a/hr/doctype/leave_control_panel/leave_control_panel.py b/hr/doctype/leave_control_panel/leave_control_panel.py index 640432109f..294701c004 100644 --- a/hr/doctype/leave_control_panel/leave_control_panel.py +++ b/hr/doctype/leave_control_panel/leave_control_panel.py @@ -33,7 +33,7 @@ class DocType: emp_query = "select name from `tabEmployee` " if flag == 1: emp_query += condition - e = sql(emp_query) + e = webnotes.conn.sql(emp_query) return e # ---------------- diff --git a/hr/doctype/salary_manager/salary_manager.py b/hr/doctype/salary_manager/salary_manager.py index ecc829f87a..48dcab1808 100644 --- a/hr/doctype/salary_manager/salary_manager.py +++ b/hr/doctype/salary_manager/salary_manager.py @@ -29,7 +29,7 @@ class DocType: cond = self.get_filter_condition() cond += self.get_joining_releiving_condition() - emp_list = sql(""" + emp_list = webnotes.conn.sql(""" select t1.name from `tabEmployee` t1, `tabSalary Structure` t2 where t1.docstatus!=2 and t2.docstatus != 2 @@ -67,7 +67,7 @@ class DocType: def get_month_details(self, year, month): - ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0] + ysd = webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0] if ysd: from dateutil.relativedelta import relativedelta import calendar, datetime @@ -95,7 +95,7 @@ class DocType: emp_list = self.get_emp_list() ss_list = [] for emp in emp_list: - if not sql("""select name from `tabSalary Slip` + if not webnotes.conn.sql("""select name from `tabSalary Slip` where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s """, (emp[0], self.doc.month, self.doc.fiscal_year, self.doc.company)): ss = webnotes.bean({ @@ -126,7 +126,7 @@ class DocType: which are not submitted """ cond = self.get_filter_condition() - ss_list = sql(""" + ss_list = webnotes.conn.sql(""" select t1.name from `tabSalary Slip` t1 where t1.docstatus = 0 and month = '%s' and fiscal_year = '%s' %s """ % (self.doc.month, self.doc.fiscal_year, cond)) @@ -188,7 +188,7 @@ class DocType: Get total salary amount from submitted salary slip based on selected criteria """ cond = self.get_filter_condition() - tot = sql(""" + tot = webnotes.conn.sql(""" select sum(rounded_total) from `tabSalary Slip` t1 where t1.docstatus = 1 and month = '%s' and fiscal_year = '%s' %s """ % (self.doc.month, self.doc.fiscal_year, cond)) @@ -201,7 +201,7 @@ class DocType: get default bank account,default salary acount from company """ amt = self.get_total_salary() - com = sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company) + com = webnotes.conn.sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company) if not com[0][0] or not com[0][1]: msgprint("You can set Default Bank Account in Company master.") diff --git a/hr/doctype/salary_manager/test_salary_manager.py b/hr/doctype/salary_manager/test_salary_manager.py index 04000f0670..13815db52b 100644 --- a/hr/doctype/salary_manager/test_salary_manager.py +++ b/hr/doctype/salary_manager/test_salary_manager.py @@ -9,7 +9,7 @@ test_records = [] # from webnotes.model.doc import Document # from webnotes.model.code import get_obj -# sql = webnotes.conn.sql +# webnotes.conn.sql = webnotes.conn.sql # # class TestSalaryManager(unittest.TestCase): # def setUp(self): @@ -20,15 +20,15 @@ test_records = [] # ss1[0].employee = emp1.name # for s in ss1: s.save(1) # for s in ss1[1:]: -# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name)) -# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name)) +# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name)) +# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name)) # # # ss2[0].employee = emp2.name # for s in ss2: s.save(1) # for s in ss2[1:]: -# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name)) -# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name)) +# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name)) +# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name)) # # sman.save() # self.sm = get_obj('Salary Manager') @@ -36,7 +36,7 @@ test_records = [] # self.sm.create_sal_slip() # # def test_creation(self): -# ssid = sql(""" +# ssid = webnotes.conn.sql(""" # select name, department # from `tabSalary Slip` # where month = '08' and fiscal_year='2011-2012'""") @@ -46,7 +46,7 @@ test_records = [] # # # def test_lwp_calc(self): -# ss = sql(""" +# ss = webnotes.conn.sql(""" # select payment_days # from `tabSalary Slip` # where month = '08' and fiscal_year='2011-2012' and employee = '%s' diff --git a/hr/doctype/salary_slip/salary_slip.py b/hr/doctype/salary_slip/salary_slip.py index 7104273170..dab026e364 100644 --- a/hr/doctype/salary_slip/salary_slip.py +++ b/hr/doctype/salary_slip/salary_slip.py @@ -31,7 +31,7 @@ class DocType(TransactionBase): def check_sal_struct(self): - struct = sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee) + struct = webnotes.conn.sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee) if not struct: msgprint("Please create Salary Structure for employee '%s'"%self.doc.employee) self.doc.employee = '' @@ -99,13 +99,13 @@ class DocType(TransactionBase): return payment_days def get_holidays_for_employee(self, m): - holidays = sql("""select t1.holiday_date + holidays = webnotes.conn.sql("""select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = %s and t1.holiday_date between %s and %s""", (self.doc.employee, m['month_start_date'], m['month_end_date'])) if not holidays: - holidays = sql("""select t1.holiday_date + holidays = webnotes.conn.sql("""select t1.holiday_date from `tabHoliday` t1, `tabHoliday List` t2 where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1 and t2.fiscal_year = %s @@ -119,7 +119,7 @@ class DocType(TransactionBase): for d in range(m['month_days']): dt = add_days(cstr(m['month_start_date']), d) if dt not in holidays: - leave = sql(""" + leave = webnotes.conn.sql(""" select t1.name, t1.half_day from `tabLeave Application` t1, `tabLeave Type` t2 where t2.name = t1.leave_type @@ -133,7 +133,7 @@ class DocType(TransactionBase): return lwp def check_existing(self): - ret_exist = sql("""select name from `tabSalary Slip` + ret_exist = webnotes.conn.sql("""select name from `tabSalary Slip` where month = %s and fiscal_year = %s and docstatus != 2 and employee = %s and name != %s""", (self.doc.month, self.doc.fiscal_year, self.doc.employee, self.doc.name)) @@ -200,9 +200,9 @@ class DocType(TransactionBase): receiver = webnotes.conn.get_value("Employee", self.doc.employee, "company_email") if receiver: subj = 'Salary Slip - ' + cstr(self.doc.month) +'/'+cstr(self.doc.fiscal_year) - earn_ret=sql("""select e_type, e_modified_amount from `tabSalary Slip Earning` + earn_ret=webnotes.conn.sql("""select e_type, e_modified_amount from `tabSalary Slip Earning` where parent = %s""", self.doc.name) - ded_ret=sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction` + ded_ret=webnotes.conn.sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction` where parent = %s""", self.doc.name) earn_table = '' diff --git a/hr/doctype/salary_structure/salary_structure.py b/hr/doctype/salary_structure/salary_structure.py index c3cd93d48c..bfa7850d51 100644 --- a/hr/doctype/salary_structure/salary_structure.py +++ b/hr/doctype/salary_structure/salary_structure.py @@ -19,7 +19,7 @@ class DocType: def get_employee_details(self): ret = {} - det = sql("""select employee_name, branch, designation, department, grade + det = webnotes.conn.sql("""select employee_name, branch, designation, department, grade from `tabEmployee` where name = %s""", self.doc.employee) if det: ret = { @@ -33,7 +33,7 @@ class DocType: return ret def get_ss_values(self,employee): - basic_info = sql("""select bank_name, bank_ac_no, esic_card_no, pf_number + basic_info = webnotes.conn.sql("""select bank_name, bank_ac_no, esic_card_no, pf_number from `tabEmployee` where name =%s""", employee) ret = {'bank_name': basic_info and basic_info[0][0] or '', 'bank_ac_no': basic_info and basic_info[0][1] or '', @@ -42,7 +42,7 @@ class DocType: return ret def make_table(self, doct_name, tab_fname, tab_name): - list1 = sql("select name from `tab%s` where docstatus != 2" % doct_name) + list1 = webnotes.conn.sql("select name from `tab%s` where docstatus != 2" % doct_name) for li in list1: child = addchild(self.doc, tab_fname, tab_name, self.doclist) if(tab_fname == 'earning_details'): @@ -57,7 +57,7 @@ class DocType: self.make_table('Deduction Type','deduction_details', 'Salary Structure Deduction') def check_existing(self): - ret = sql("""select name from `tabSalary Structure` where is_active = 'Yes' + ret = webnotes.conn.sql("""select name from `tabSalary Structure` where is_active = 'Yes' and employee = %s and name!=%s""", (self.doc.employee,self.doc.name)) if ret and self.doc.is_active=='Yes': msgprint(_("""Another Salary Structure '%s' is active for employee '%s'. diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 84a3d6c13b..20c1141093 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -17,7 +17,7 @@ class DocType: self.doclist = doclist def autoname(self): - last_name = sql("""select max(name) from `tabBOM` + last_name = webnotes.conn.sql("""select max(name) from `tabBOM` where name like "BOM/%s/%%" """ % cstr(self.doc.item).replace('"', '\\"')) if last_name: idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1 @@ -143,7 +143,7 @@ class DocType: webnotes.bean(self.doclist).update_after_submit() def get_bom_unitcost(self, bom_no): - bom = sql("""select name, total_cost/quantity as unit_cost from `tabBOM` + bom = webnotes.conn.sql("""select name, total_cost/quantity as unit_cost from `tabBOM` where is_active = 1 and name = %s""", bom_no, as_dict=1) return bom and bom[0]['unit_cost'] or 0 @@ -155,7 +155,7 @@ class DocType: from stock.utils import get_incoming_rate dt = self.doc.costing_date or nowdate() time = self.doc.costing_date == nowdate() and now().split()[1] or '23:59' - warehouse = sql("select warehouse from `tabBin` where item_code = %s", args['item_code']) + warehouse = webnotes.conn.sql("select warehouse from `tabBin` where item_code = %s", args['item_code']) rate = [] for wh in warehouse: r = get_incoming_rate({ @@ -183,7 +183,7 @@ class DocType: if not self.doc.is_active: webnotes.conn.set(self.doc, "is_default", 0) - sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s", + webnotes.conn.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s", (self.doc.item, self.doc.name)) def clear_operations(self): @@ -249,7 +249,7 @@ class DocType: def validate_bom_no(self, item, bom_no, idx): """Validate BOM No of sub-contracted items""" - bom = sql("""select name from `tabBOM` where name = %s and item = %s + bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s and is_active=1 and docstatus=1""", (bom_no, item), as_dict =1) if not bom: @@ -271,7 +271,7 @@ class DocType: for d in check_list: bom_list, count = [self.doc.name], 0 while (len(bom_list) > count ): - boms = sql(" select %s from `tabBOM Item` where %s = '%s' " % + boms = webnotes.conn.sql(" select %s from `tabBOM Item` where %s = '%s' " % (d[0], d[1], cstr(bom_list[count]))) count = count + 1 for b in boms: @@ -363,7 +363,7 @@ class DocType: def get_child_exploded_items(self, bom_no, qty): """ Add all items from Flat BOM of child BOM""" - child_fb_items = sql("""select item_code, description, stock_uom, qty, rate, + child_fb_items = webnotes.conn.sql("""select item_code, description, stock_uom, qty, rate, qty_consumed_per_unit from `tabBOM Explosion Item` where parent = %s and docstatus = 1""", bom_no, as_dict = 1) @@ -389,12 +389,12 @@ class DocType: ch.save(1) def get_parent_bom_list(self, bom_no): - p_bom = sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no) + p_bom = webnotes.conn.sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no) return p_bom and [i[0] for i in p_bom] or [] def validate_bom_links(self): if not self.doc.is_active: - act_pbom = sql("""select distinct bom_item.parent from `tabBOM Item` bom_item + act_pbom = webnotes.conn.sql("""select distinct bom_item.parent from `tabBOM Item` bom_item where bom_item.bom_no = %s and bom_item.docstatus = 1 and exists (select * from `tabBOM` where name = bom_item.parent and docstatus = 1 and is_active = 1)""", self.doc.name) diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 28adc65e36..b9d15fdf96 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -22,14 +22,14 @@ class DocType: "In Process", "Completed", "Cancelled"]) if self.doc.production_item : - item_detail = sql("select name from `tabItem` where name = '%s' and docstatus != 2" + item_detail = webnotes.conn.sql("select name from `tabItem` where name = '%s' and docstatus != 2" % self.doc.production_item, as_dict = 1) if not item_detail: msgprint("Item '%s' does not exist or cancelled in the system." % cstr(self.doc.production_item), raise_exception=1) if self.doc.bom_no: - bom = sql("""select name from `tabBOM` where name=%s and docstatus=1 + bom = webnotes.conn.sql("""select name from `tabBOM` where name=%s and docstatus=1 and is_active=1 and item=%s""" , (self.doc.bom_no, self.doc.production_item), as_dict =1) if not bom: @@ -103,7 +103,7 @@ class DocType: def on_cancel(self): # Check whether any stock entry exists against this Production Order - stock_entry = sql("""select name from `tabStock Entry` + stock_entry = webnotes.conn.sql("""select name from `tabStock Entry` where production_order = %s and docstatus = 1""", self.doc.name) if stock_entry: msgprint("""Submitted Stock Entry %s exists against this production order. diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py index c150be3ff6..5480f177d9 100644 --- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -18,7 +18,7 @@ class DocType: def get_so_details(self, so): """Pull other details from so""" - so = sql("""select transaction_date, customer, grand_total + so = webnotes.conn.sql("""select transaction_date, customer, grand_total from `tabSales Order` where name = %s""", so, as_dict = 1) ret = { 'sales_order_date': so and so[0]['transaction_date'] or '', @@ -30,7 +30,7 @@ class DocType: def get_item_details(self, item_code): """ Pull other item details from item master""" - item = sql("""select description, stock_uom, default_bom + item = webnotes.conn.sql("""select description, stock_uom, default_bom from `tabItem` where name = %s""", item_code, as_dict =1) ret = { 'description' : item and item[0]['description'], @@ -62,7 +62,7 @@ class DocType: if self.doc.fg_item: item_filter += ' and item.name = "' + self.doc.fg_item + '"' - open_so = sql(""" + open_so = webnotes.conn.sql(""" select distinct so.name, so.transaction_date, so.customer, so.grand_total from `tabSales Order` so, `tabSales Order Item` so_item where so_item.parent = so.name @@ -107,7 +107,7 @@ class DocType: msgprint("Please enter sales order in the above table") return [] - items = sql("""select distinct parent, item_code, reserved_warehouse, + items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse, (qty - ifnull(delivered_qty, 0)) as pending_qty from `tabSales Order Item` so_item where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0) @@ -116,7 +116,7 @@ class DocType: or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \ (", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1) - dnpi_items = sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse, + dnpi_items = webnotes.conn.sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse, (((so_item.qty - ifnull(so_item.delivered_qty, 0)) * dnpi.qty) / so_item.qty) as pending_qty from `tabSales Order Item` so_item, `tabDelivery Note Packing Item` dnpi @@ -135,7 +135,7 @@ class DocType: self.clear_item_table() for p in items: - item_details = sql("""select description, stock_uom, default_bom + item_details = webnotes.conn.sql("""select description, stock_uom, default_bom from tabItem where name=%s""", p['item_code']) pi = addchild(self.doc, 'pp_details', 'Production Plan Item', self.doclist) pi.sales_order = p['parent'] @@ -161,7 +161,7 @@ class DocType: msgprint("Please enter bom no for item: %s at row no: %s" % (d.item_code, d.idx), raise_exception=1) else: - bom = sql("""select name from `tabBOM` where name = %s and item = %s + bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s and docstatus = 1 and is_active = 1""", (d.bom_no, d.item_code), as_dict = 1) if not bom: @@ -242,7 +242,7 @@ class DocType: for bom in bom_dict: if self.doc.use_multi_level_bom: # get all raw materials with sub assembly childs - fl_bom_items = sql("""select fb.item_code, + fl_bom_items = webnotes.conn.sql("""select fb.item_code, ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty, fb.description, fb.stock_uom, it.min_order_qty from `tabBOM Explosion Item` fb,`tabItem` it @@ -253,7 +253,7 @@ class DocType: else: # Get all raw materials considering SA items as raw materials, # so no childs of SA items - fl_bom_items = sql("""select bom_item.item_code, + fl_bom_items = webnotes.conn.sql("""select bom_item.item_code, ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s, bom_item.description, bom_item.stock_uom, item.min_order_qty from `tabBOM Item` bom_item, tabItem item @@ -273,7 +273,7 @@ class DocType: 'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']] for d in self.item_dict: item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]]) - item_qty= sql("""select warehouse, indented_qty, ordered_qty, actual_qty + item_qty= webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty from `tabBin` where item_code = %s""", d) i_qty, o_qty, a_qty = 0, 0, 0 for w in item_qty: diff --git a/manufacturing/doctype/workstation/workstation.py b/manufacturing/doctype/workstation/workstation.py index 56833a9e5b..cc129340e4 100644 --- a/manufacturing/doctype/workstation/workstation.py +++ b/manufacturing/doctype/workstation/workstation.py @@ -17,9 +17,9 @@ class DocType: self.doclist = doclist def update_bom_operation(self): - bom_list = sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name) + bom_list = webnotes.conn.sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name) for bom_no in bom_list: - sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name)) + webnotes.conn.sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name)) def on_update(self): webnotes.conn.set(self.doc, 'overhead', flt(self.doc.hour_rate_electricity) + flt(self.doc.hour_rate_consumable) + flt(self.doc.hour_rate_rent)) diff --git a/projects/doctype/task/task.py b/projects/doctype/task/task.py index 856be5cc88..fb9b6ab6a6 100644 --- a/projects/doctype/task/task.py +++ b/projects/doctype/task/task.py @@ -16,13 +16,13 @@ class DocType: self.doclist = doclist def get_project_details(self): - cust = sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project) + cust = webnotes.conn.sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project) if cust: ret = {'customer': cust and cust[0][0] or '', 'customer_name': cust and cust[0][1] or ''} return ret def get_customer_details(self): - cust = sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer) + cust = webnotes.conn.sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer) if cust: ret = {'customer_name': cust and cust[0][0] or ''} return ret diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py index 0c2bf616dd..78fad0034f 100644 --- a/selling/doctype/customer/customer.py +++ b/selling/doctype/customer/customer.py @@ -30,7 +30,7 @@ class DocType(TransactionBase): return webnotes.conn.get_value('Company', self.doc.company, 'abbr') def get_receivables_group(self): - g = sql("select receivables_group from tabCompany where name=%s", self.doc.company) + g = webnotes.conn.sql("select receivables_group from tabCompany where name=%s", self.doc.company) g = g and g[0][0] or '' if not g: msgprint("Update Company master, assign a default group for Receivables") @@ -46,7 +46,7 @@ class DocType(TransactionBase): def update_lead_status(self): if self.doc.lead_name: - sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name) + webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name) def create_account_head(self): if self.doc.company : @@ -131,7 +131,7 @@ class DocType(TransactionBase): def delete_customer_account(self): """delete customer's ledger if exist and check balance before deletion""" - acc = sql("select name from `tabAccount` where master_type = 'Customer' \ + acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Customer' \ and master_name = %s and docstatus < 2", self.doc.name) if acc: from webnotes.model import delete_doc @@ -142,7 +142,7 @@ class DocType(TransactionBase): self.delete_customer_contact() self.delete_customer_account() if self.doc.lead_name: - sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name) + webnotes.conn.sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name) def on_rename(self, new, old, merge=False): #update customer_name if not naming series diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index c0ef242baa..eb3c69571a 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -37,7 +37,7 @@ class DocType(SellingController): webnotes.conn.set(self.doc, 'status', status) def check_status(self): - chk = sql("select status from `tabLead` where name=%s", self.doc.name) + chk = webnotes.conn.sql("select status from `tabLead` where name=%s", self.doc.name) chk = chk and chk[0][0] or '' return cstr(chk) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index df6861a773..284c5e0545 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -26,7 +26,7 @@ class DocType(TransactionBase): }) def get_item_details(self, item_code): - item = sql("""select item_name, stock_uom, description_html, description, item_group, brand + item = webnotes.conn.sql("""select item_name, stock_uom, description_html, description, item_group, brand from `tabItem` where name = %s""", item_code, as_dict=1) ret = { 'item_name': item and item[0]['item_name'] or '', @@ -38,7 +38,7 @@ class DocType(TransactionBase): return ret def get_cust_address(self,name): - details = sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1) + details = webnotes.conn.sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1) if details: ret = { 'customer_name': details and details[0]['customer_name'] or '', @@ -48,7 +48,7 @@ class DocType(TransactionBase): } # ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query) - contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1) + contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1) ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or '' ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or '' @@ -61,7 +61,7 @@ class DocType(TransactionBase): def get_contact_details(self, arg): arg = eval(arg) - contact = sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1) + contact = webnotes.conn.sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1) ret = { 'contact_no' : contact and contact[0]['contact_no'] or '', 'email_id' : contact and contact[0]['email_id'] or '' @@ -135,7 +135,7 @@ class DocType(TransactionBase): webnotes.conn.set(self.doc, 'status', 'Submitted') def on_cancel(self): - chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) + chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) if chk: msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.") raise Exception @@ -143,7 +143,7 @@ class DocType(TransactionBase): webnotes.conn.set(self.doc, 'status', 'Cancelled') def declare_enquiry_lost(self,arg): - chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) + chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) if chk: msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.") raise Exception diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 8ac0d1925a..8a3bef10e9 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -77,7 +77,7 @@ class DocType(SellingController): if self.doc.order_type in ['Maintenance', 'Service']: for d in getlist(self.doclist, 'quotation_details'): - is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code) + is_service_item = webnotes.conn.sql("select is_service_item from `tabItem` where name=%s", d.item_code) is_service_item = is_service_item and is_service_item[0][0] or 'No' if is_service_item == 'No': @@ -85,7 +85,7 @@ class DocType(SellingController): raise Exception else: for d in getlist(self.doclist, 'quotation_details'): - is_sales_item = sql("select is_sales_item from `tabItem` where name=%s", d.item_code) + is_sales_item = webnotes.conn.sql("select is_sales_item from `tabItem` where name=%s", d.item_code) is_sales_item = is_sales_item and is_sales_item[0][0] or 'No' if is_sales_item == 'No': @@ -141,18 +141,18 @@ class DocType(SellingController): if prevdoc: if flag == 'submit': #on submit - sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc) + webnotes.conn.sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc) elif flag == 'cancel': #on cancel - sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc) + webnotes.conn.sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc) elif flag == 'order lost': #order lost - sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc) + webnotes.conn.sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc) elif flag == 'order confirm': #order confirm - sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc) + webnotes.conn.sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc) # declare as order lost #------------------------- def declare_order_lost(self, arg): - chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name) + chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name) if chk: msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.") raise Exception diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 5043a77d76..c9ef5d3bba 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -87,14 +87,14 @@ class DocType(SellingController): # used for production plan d.transaction_date = self.doc.transaction_date - tot_avail_qty = sql("select projected_qty from `tabBin` \ + tot_avail_qty = webnotes.conn.sql("select projected_qty from `tabBin` \ where item_code = '%s' and warehouse = '%s'" % (d.item_code,d.reserved_warehouse)) d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0 def validate_sales_mntc_quotation(self): for d in getlist(self.doclist, 'sales_order_details'): if d.prevdoc_docname: - res = sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type)) + res = webnotes.conn.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type)) if not res: msgprint("""Order Type (%s) should be same in Quotation: %s \ and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname)) @@ -111,7 +111,7 @@ class DocType(SellingController): def validate_proj_cust(self): if self.doc.project_name and self.doc.customer_name: - res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer)) + res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer)) if not res: msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name)) raise Exception @@ -167,28 +167,28 @@ class DocType(SellingController): def check_prev_docstatus(self): for d in getlist(self.doclist, 'sales_order_details'): - cancel_quo = sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname) + cancel_quo = webnotes.conn.sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname) if cancel_quo: msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !") raise Exception , "Validation Error. " def update_enquiry_status(self, prevdoc, flag): - enq = sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc) + enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc) if enq: - sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0])) + webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0])) def update_prevdoc_status(self, flag): for d in getlist(self.doclist, 'sales_order_details'): if d.prevdoc_docname: if flag=='submit': - sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname) + webnotes.conn.sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname) #update enquiry self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed') elif flag == 'cancel': - chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name)) + chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name)) if not chk: - sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname) + webnotes.conn.sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname) #update enquiry self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent') @@ -218,35 +218,35 @@ class DocType(SellingController): def check_nextdoc_docstatus(self): # Checks Delivery Note - submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) if submit_dn: msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) # Checks Sales Invoice - submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_rv = webnotes.conn.sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name)) if submit_rv: msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) #check maintenance schedule - submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) + submit_ms = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) if submit_ms: msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) # check maintenance visit - submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) + submit_mv = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) if submit_mv: msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) # check production order - pro_order = sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name) + pro_order = webnotes.conn.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name) if pro_order: msgprint("""Production Order: %s exists against this sales order. Please cancel production order first and then cancel this sales order""" % pro_order[0][0], raise_exception=1) def check_modified_date(self): - mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name) - date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) + mod_db = webnotes.conn.sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name) + date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) if date_diff and date_diff[0][0]: msgprint("%s: %s has been modified after you have opened. Please Refresh" % (self.doc.doctype, self.doc.name), raise_exception=1) diff --git a/selling/doctype/sms_center/sms_center.py b/selling/doctype/sms_center/sms_center.py index 8db20b0275..6f16798d8b 100644 --- a/selling/doctype/sms_center/sms_center.py +++ b/selling/doctype/sms_center/sms_center.py @@ -28,15 +28,15 @@ class DocType: where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % self.doc.sales_partner or " and ifnull(sales_partner, '') != ''" if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']: - rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause) + rec = webnotes.conn.sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause) elif self.doc.send_to == 'All Lead (Open)': - rec = sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'") + rec = webnotes.conn.sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'") elif self.doc.send_to == 'All Employee (Active)': where_clause = self.doc.department and " and department = '%s'" % self.doc.department or "" where_clause += self.doc.branch and " and branch = '%s'" % self.doc.branch or "" - rec = sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause) + rec = webnotes.conn.sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause) elif self.doc.send_to == 'All Sales Person': - rec = sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''") + rec = webnotes.conn.sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''") rec_list = '' for d in rec: rec_list += d[0] + ' - ' + d[1] + '\n' diff --git a/setup/doctype/authorization_control/authorization_control.py b/setup/doctype/authorization_control/authorization_control.py index 26f7705af3..533f3988e3 100644 --- a/setup/doctype/authorization_control/authorization_control.py +++ b/setup/doctype/authorization_control/authorization_control.py @@ -27,10 +27,10 @@ class DocType(TransactionBase): amt_list.append(flt(x[0])) max_amount = max(amt_list) - app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company)) + app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company)) if not app_dtl: - app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on)) + app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on)) for d in app_dtl: if(d[0]): appr_users.append(d[0]) if(d[1]): appr_roles.append(d[1]) @@ -57,18 +57,18 @@ class DocType(TransactionBase): add_cond1,add_cond2 = '','' if based_on == 'Itemwise Discount': add_cond1 += " and master_name = '"+cstr(item)+"'" - itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company)) + itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company)) if not itemwise_exists: - itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on)) + itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on)) if itemwise_exists: self.get_appr_user_role(itemwise_exists, doctype_name, total, based_on, cond+add_cond1, item,company) chk = 0 if chk == 1: if based_on == 'Itemwise Discount': add_cond2 += " and ifnull(master_name,'') = ''" - appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company)) + appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company)) if not appr: - appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on)) + appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on)) self.get_appr_user_role(appr, doctype_name, total, based_on, cond+add_cond2, item, company) @@ -111,7 +111,7 @@ class DocType(TransactionBase): # ================ # Check for authorization set for individual user - based_on = [x[0] for x in sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))] + based_on = [x[0] for x in webnotes.conn.sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))] for d in based_on: self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 1, company) @@ -123,7 +123,7 @@ class DocType(TransactionBase): # Specific Role # =============== # Check for authorization set on particular roles - based_on = [x[0] for x in sql("""select based_on + based_on = [x[0] for x in webnotes.conn.sql("""select based_on from `tabAuthorization Rule` where transaction = %s and system_role IN (%s) and based_on IN (%s) and (company = %s or ifnull(company,'')='') @@ -147,9 +147,9 @@ class DocType(TransactionBase): # payroll related check def get_value_based_rule(self,doctype_name,employee,total_claimed_amount,company): val_lst =[] - val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company)) + val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company)) if not val: - val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount)) + val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount)) if val: val_lst = [y[0] for y in val] @@ -157,9 +157,9 @@ class DocType(TransactionBase): val_lst.append(0) max_val = max(val_lst) - rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1) + rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1) if not rule: - rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1) + rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1) return rule @@ -174,9 +174,9 @@ class DocType(TransactionBase): if doctype_name == 'Expense Claim': rule = self.get_value_based_rule(doctype_name,doc_obj.doc.employee,doc_obj.doc.total_claimed_amount, doc_obj.doc.company) elif doctype_name == 'Appraisal': - rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1) + rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1) if not rule: - rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1) + rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1) if rule: for m in rule: @@ -184,7 +184,7 @@ class DocType(TransactionBase): if m['approving_user']: app_specific_user.append(m['approving_user']) elif m['approving_role']: - user_lst = [z[0] for z in sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])] + user_lst = [z[0] for z in webnotes.conn.sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])] for x in user_lst: if not x in app_user: app_user.append(x) diff --git a/setup/doctype/authorization_rule/authorization_rule.py b/setup/doctype/authorization_rule/authorization_rule.py index 5192ebf769..ea22b154b9 100644 --- a/setup/doctype/authorization_rule/authorization_rule.py +++ b/setup/doctype/authorization_rule/authorization_rule.py @@ -18,7 +18,7 @@ class DocType: def check_duplicate_entry(self): - exists = sql("""select name, docstatus from `tabAuthorization Rule` + exists = webnotes.conn.sql("""select name, docstatus from `tabAuthorization Rule` where transaction = %s and based_on = %s and system_user = %s and system_role = %s and approving_user = %s and approving_role = %s and to_emp =%s and to_designation=%s and name != %s""", @@ -38,12 +38,12 @@ class DocType: def validate_master_name(self): if self.doc.based_on == 'Customerwise Discount' and \ - not sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \ + not webnotes.conn.sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \ (self.doc.master_name)): msgprint("Please select valid Customer Name for Customerwise Discount", raise_exception=1) elif self.doc.based_on == 'Itemwise Discount' and \ - not sql("select name from tabItem where name = '%s' and docstatus != 2" % \ + not webnotes.conn.sql("select name from tabItem where name = '%s' and docstatus != 2" % \ (self.doc.master_name)): msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1) elif (self.doc.based_on == 'Grand Total' or \ @@ -64,7 +64,7 @@ class DocType: Applicable To (Role).", raise_exception=1) elif self.doc.system_user and self.doc.approving_role and \ has_common([self.doc.approving_role], [x[0] for x in \ - sql("select role from `tabUserRole` where parent = '%s'" % \ + webnotes.conn.sql("select role from `tabUserRole` where parent = '%s'" % \ (self.doc.system_user))]): msgprint("System User : %s is assigned role : %s. So rule does not make sense" % (self.doc.system_user,self.doc.approving_role), raise_exception=1) diff --git a/setup/doctype/customer_group/customer_group.py b/setup/doctype/customer_group/customer_group.py index 8b68cc50e4..1264c1b3ec 100644 --- a/setup/doctype/customer_group/customer_group.py +++ b/setup/doctype/customer_group/customer_group.py @@ -14,7 +14,7 @@ class DocType(DocTypeNestedSet): self.nsm_parent_field = 'parent_customer_group'; def validate(self): - if sql("select name from `tabCustomer Group` where name = %s and docstatus = 2", + if webnotes.conn.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2", (self.doc.customer_group_name)): msgprint("""Another %s record is trashed. To untrash please go to Setup -> Recycle Bin.""" % @@ -32,7 +32,7 @@ class DocType(DocTypeNestedSet): self.doc.name, raise_exception=1) def on_trash(self): - cust = sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s", + cust = webnotes.conn.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s", self.doc.name) cust = [d[0] for d in cust] if cust: @@ -41,7 +41,7 @@ class DocType(DocTypeNestedSet): To trash/delete this, remove/change customer group in customer master""" % (self.doc.name, cust or ''), raise_exception=1) - if sql("select name from `tabCustomer Group` where parent_customer_group = %s \ + if webnotes.conn.sql("select name from `tabCustomer Group` where parent_customer_group = %s \ and docstatus != 2", self.doc.name): msgprint("Child customer group exists for this customer group. \ You can not trash/cancel/delete this customer group.", raise_exception=1) diff --git a/setup/doctype/naming_series/naming_series.py b/setup/doctype/naming_series/naming_series.py index 6312801fe8..4e85b15f6d 100644 --- a/setup/doctype/naming_series/naming_series.py +++ b/setup/doctype/naming_series/naming_series.py @@ -22,7 +22,7 @@ class DocType: where fieldname='naming_series'""") )))), "prefixes": "\n".join([''] + [i[0] for i in - sql("""select name from tabSeries""")]) + webnotes.conn.sql("""select name from tabSeries""")]) } def scrub_options_list(self, ol): @@ -125,12 +125,12 @@ class DocType: def insert_series(self, series): """insert series if missing""" if not webnotes.conn.exists('Series', series): - sql("insert into tabSeries (name, current) values (%s,0)", (series)) + webnotes.conn.sql("insert into tabSeries (name, current) values (%s,0)", (series)) def update_series_start(self): if self.doc.prefix: self.insert_series(self.doc.prefix) - sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix)) + webnotes.conn.sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix)) msgprint("Series Updated Successfully") else: msgprint("Please select prefix first") diff --git a/setup/doctype/notification_control/notification_control.py b/setup/doctype/notification_control/notification_control.py index 23493624dd..0a151152d6 100644 --- a/setup/doctype/notification_control/notification_control.py +++ b/setup/doctype/notification_control/notification_control.py @@ -13,7 +13,7 @@ class DocType: def get_message(self, arg): fn = arg.lower().replace(' ', '_') + '_message' - v = sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control')) + v = webnotes.conn.sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control')) return v and v[0][0] or '' def set_message(self, arg = ''): diff --git a/setup/doctype/sales_partner/sales_partner.py b/setup/doctype/sales_partner/sales_partner.py index 8915ff1cc0..79a59db71a 100644 --- a/setup/doctype/sales_partner/sales_partner.py +++ b/setup/doctype/sales_partner/sales_partner.py @@ -23,7 +23,7 @@ class DocType: def get_contacts(self,nm): if nm: - contact_details =webnotes.conn.convert_to_lists(sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where sales_partner = '%s'"%nm)) + contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where sales_partner = '%s'"%nm)) return contact_details else: return '' diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 954ef783a4..8c892c1324 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -60,7 +60,7 @@ class DocType: self.doc.save() def get_first_sle(self): - sle = sql(""" + sle = webnotes.conn.sql(""" select * from `tabStock Ledger Entry` where item_code = %s and warehouse = %s diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index ce06ce3d0b..5242f60ea6 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -57,7 +57,7 @@ class DocType(SellingController): def set_actual_qty(self): for d in getlist(self.doclist, 'delivery_note_details'): if d.item_code and d.warehouse: - actual_qty = sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d.item_code, d.warehouse)) + actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d.item_code, d.warehouse)) d.actual_qty = actual_qty and flt(actual_qty[0][0]) or 0 @@ -133,7 +133,7 @@ class DocType(SellingController): def validate_proj_cust(self): """check for does customer belong to same project as entered..""" if self.doc.project_name and self.doc.customer: - res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer)) + res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer)) if not res: msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name)) raise Exception @@ -167,11 +167,11 @@ class DocType(SellingController): def update_current_stock(self): for d in getlist(self.doclist, 'delivery_note_details'): - bin = sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) + bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 for d in getlist(self.doclist, 'packing_details'): - bin = sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) + bin = webnotes.conn.sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0 @@ -266,12 +266,12 @@ class DocType(SellingController): webnotes.msgprint("Packing Error:\n" + err_msg, raise_exception=1) def check_next_docstatus(self): - submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.delivery_note = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_rv = webnotes.conn.sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.delivery_note = '%s' and t1.docstatus = 1" % (self.doc.name)) if submit_rv: msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted !") raise Exception , "Validation Error." - submit_in = sql("select t1.name from `tabInstallation Note` t1, `tabInstallation Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_in = webnotes.conn.sql("select t1.name from `tabInstallation Note` t1, `tabInstallation Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) if submit_in: msgprint("Installation Note : "+cstr(submit_in[0][0]) +" has already been submitted !") raise Exception , "Validation Error." diff --git a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py index 5275632054..b9bbb068f1 100644 --- a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py +++ b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py @@ -32,7 +32,7 @@ class DocType: self.doclist = self.doc.clear_table(self.doclist,'lc_pr_details',1) self.check_mandatory() - pr = sql("select name from `tabPurchase Receipt` where docstatus = 1 and posting_date >= '%s' and posting_date <= '%s' and currency = '%s' order by name " % (self.doc.from_pr_date, self.doc.to_pr_date, self.doc.currency), as_dict = 1) + pr = webnotes.conn.sql("select name from `tabPurchase Receipt` where docstatus = 1 and posting_date >= '%s' and posting_date <= '%s' and currency = '%s' order by name " % (self.doc.from_pr_date, self.doc.to_pr_date, self.doc.currency), as_dict = 1) if len(pr)>200: msgprint("Please enter date of shorter duration as there are too many purchase receipt, hence it cannot be loaded.", raise_exception=1) @@ -50,14 +50,14 @@ class DocType: def validate_selected_pr(self): """Validate selected PR as submitted""" - invalid_pr = sql("SELECT name FROM `tabPurchase Receipt` WHERE docstatus != 1 and name in (%s)" % ("'" + "', '".join(self.selected_pr) + "'")) + invalid_pr = webnotes.conn.sql("SELECT name FROM `tabPurchase Receipt` WHERE docstatus != 1 and name in (%s)" % ("'" + "', '".join(self.selected_pr) + "'")) if invalid_pr: msgprint("Selected purchase receipts must be submitted. Following PR are not submitted: %s" % invalid_pr, raise_exception=1) def get_total_amt(self): """ Get sum of net total of all selected PR""" - return sql("SELECT SUM(net_total) FROM `tabPurchase Receipt` WHERE name in (%s)" % ("'" + "', '".join(self.selected_pr) + "'"))[0][0] + return webnotes.conn.sql("SELECT SUM(net_total) FROM `tabPurchase Receipt` WHERE name in (%s)" % ("'" + "', '".join(self.selected_pr) + "'"))[0][0] def add_charges_in_pr(self): @@ -73,7 +73,7 @@ class DocType: self.prwise_cost[pr] = self.prwise_cost.get(pr, 0) + amt cumulative_grand_total += amt - pr_oc_row = sql("select name from `tabPurchase Taxes and Charges` where parent = %s and category = 'Valuation' and add_deduct_tax = 'Add' and charge_type = 'Actual' and account_head = %s",(pr, lc.account_head)) + pr_oc_row = webnotes.conn.sql("select name from `tabPurchase Taxes and Charges` where parent = %s and category = 'Valuation' and add_deduct_tax = 'Add' and charge_type = 'Actual' and account_head = %s",(pr, lc.account_head)) if not pr_oc_row: # add if not exists ch = addchild(pr_obj.doc, 'purchase_tax_details', 'Purchase Taxes and Charges') ch.category = 'Valuation' @@ -88,7 +88,7 @@ class DocType: ch.idx = 500 # add at the end ch.save(1) else: # overwrite if exists - sql("update `tabPurchase Taxes and Charges` set rate = %s, tax_amount = %s where name = %s and parent = %s ", (amt, amt, pr_oc_row[0][0], pr)) + webnotes.conn.sql("update `tabPurchase Taxes and Charges` set rate = %s, tax_amount = %s where name = %s and parent = %s ", (amt, amt, pr_oc_row[0][0], pr)) def reset_other_charges(self, pr_obj): @@ -200,9 +200,9 @@ class DocType: d.save() if d.serial_no: self.update_serial_no(d.serial_no, d.valuation_rate) - sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name)) + webnotes.conn.sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name)) - res = sql("""select item_code, warehouse, posting_date, posting_time + res = webnotes.conn.sql("""select item_code, warehouse, posting_date, posting_time from `tabStock Ledger Entry` where voucher_detail_no = %s LIMIT 1""", d.name, as_dict=1) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 084f30cd59..1d48975b37 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -216,7 +216,7 @@ class DocType(BuyingController): def validate_inspection(self): for d in getlist(self.doclist, 'purchase_receipt_details'): #Enter inspection date for all items that require inspection - ins_reqd = sql("select inspection_required from `tabItem` where name = %s", + ins_reqd = webnotes.conn.sql("select inspection_required from `tabItem` where name = %s", (d.item_code,), as_dict = 1) ins_reqd = ins_reqd and ins_reqd[0]['inspection_required'] or 'No' if ins_reqd == 'Yes' and not d.qa_no: @@ -269,7 +269,7 @@ class DocType(BuyingController): sr.save() def check_next_docstatus(self): - submit_rv = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_rv = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % (self.doc.name)) if submit_rv: msgprint("Purchase Invoice : " + cstr(self.submit_rv[0][0]) + " has already been submitted !") raise Exception , "Validation Error." @@ -282,7 +282,7 @@ class DocType(BuyingController): # 1.Check if Purchase Invoice has been submitted against current Purchase Order # pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Invoice', docname = self.doc.name, detail_doctype = 'Purchase Invoice Item') - submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % self.doc.name) + submitted = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % self.doc.name) if submitted: msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !") raise Exception @@ -313,7 +313,7 @@ class DocType(BuyingController): def get_current_stock(self): for d in getlist(self.doclist, 'pr_raw_material_details'): if self.doc.supplier_warehouse: - bin = sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.doc.supplier_warehouse), as_dict = 1) + bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.doc.supplier_warehouse), as_dict = 1) d.current_stock = bin and flt(bin[0]['actual_qty']) or 0 diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index b5e1edf09c..1fdd609a62 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -387,7 +387,7 @@ class DocType(StockController): def get_item_details(self, arg): arg = json.loads(arg) - item = sql("""select stock_uom, description, item_name from `tabItem` + item = webnotes.conn.sql("""select stock_uom, description, item_name from `tabItem` where name = %s and (ifnull(end_of_life,'')='' or end_of_life ='0000-00-00' or end_of_life > now())""", (arg.get('item_code')), as_dict = 1) if not item: @@ -411,7 +411,7 @@ class DocType(StockController): def get_uom_details(self, arg = ''): arg, ret = eval(arg), {} - uom = sql("""select conversion_factor from `tabUOM Conversion Detail` + uom = webnotes.conn.sql("""select conversion_factor from `tabUOM Conversion Detail` where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1) if not uom: msgprint("There is no Conversion Factor for UOM '%s' in Item '%s'" % (arg['uom'], @@ -522,7 +522,7 @@ class DocType(StockController): if self.doc.use_multi_level_bom: # get all raw materials with sub assembly childs - fl_bom_sa_child_item = sql("""select + fl_bom_sa_child_item = webnotes.conn.sql("""select fb.item_code, ifnull(sum(fb.qty_consumed_per_unit),0)*%s as qty, fb.description, @@ -542,7 +542,7 @@ class DocType(StockController): _make_items_dict(fl_bom_sa_child_item) else: # get only BOM items - fl_bom_sa_items = sql("""select + fl_bom_sa_items = webnotes.conn.sql("""select `tabItem`.item_code, ifnull(sum(`tabBOM Item`.qty_consumed_per_unit), 0) *%s as qty, `tabItem`.description, @@ -600,7 +600,7 @@ class DocType(StockController): def get_issued_qty(self): issued_item_qty = {} - result = sql("""select t1.item_code, sum(t1.qty) + result = webnotes.conn.sql("""select t1.item_code, sum(t1.qty) from `tabStock Entry Detail` t1, `tabStock Entry` t2 where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1 and t2.purpose = 'Material Transfer' @@ -666,7 +666,7 @@ class DocType(StockController): def get_cust_addr(self): from utilities.transaction_base import get_default_address, get_address_display - res = sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer) + res = webnotes.conn.sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer) address_display = None customer_address = get_default_address("customer", self.doc.customer) if customer_address: @@ -687,7 +687,7 @@ class DocType(StockController): def get_supp_addr(self): from utilities.transaction_base import get_default_address, get_address_display - res = sql("""select supplier_name from `tabSupplier` + res = webnotes.conn.sql("""select supplier_name from `tabSupplier` where name=%s""", self.doc.supplier) address_display = None supplier_address = get_default_address("customer", self.doc.customer) diff --git a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py index 2ec9debf7f..1f1bafabc8 100644 --- a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py +++ b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py @@ -33,7 +33,7 @@ class DocType: msgprint("Please Enter Conversion Factor.") raise Exception - stock_uom = sql("select stock_uom from `tabItem` where name = '%s'" % self.doc.item_code) + stock_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'" % self.doc.item_code) stock_uom = stock_uom and stock_uom[0][0] if cstr(self.doc.new_stock_uom) == cstr(stock_uom): msgprint("Item Master is already updated with New Stock UOM " + cstr(self.doc.new_stock_uom)) @@ -49,9 +49,9 @@ class DocType: def update_bin(self): # update bin if flt(self.doc.conversion_factor) != flt(1): - sql("update `tabBin` set stock_uom = '%s' , indented_qty = ifnull(indented_qty,0) * %s, ordered_qty = ifnull(ordered_qty,0) * %s, reserved_qty = ifnull(reserved_qty,0) * %s, planned_qty = ifnull(planned_qty,0) * %s, projected_qty = actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.item_code) ) + webnotes.conn.sql("update `tabBin` set stock_uom = '%s' , indented_qty = ifnull(indented_qty,0) * %s, ordered_qty = ifnull(ordered_qty,0) * %s, reserved_qty = ifnull(reserved_qty,0) * %s, planned_qty = ifnull(planned_qty,0) * %s, projected_qty = actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.item_code) ) else: - sql("update `tabBin` set stock_uom = '%s' where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.item_code) ) + webnotes.conn.sql("update `tabBin` set stock_uom = '%s' where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.item_code) ) # acknowledge user msgprint(" All Bins Updated Successfully.") @@ -61,16 +61,16 @@ class DocType: from stock.stock_ledger import update_entries_after if flt(self.doc.conversion_factor) != flt(1): - sql("update `tabStock Ledger Entry` set stock_uom = '%s', actual_qty = ifnull(actual_qty,0) * '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.item_code)) + webnotes.conn.sql("update `tabStock Ledger Entry` set stock_uom = '%s', actual_qty = ifnull(actual_qty,0) * '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.item_code)) else: - sql("update `tabStock Ledger Entry` set stock_uom = '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.item_code)) + webnotes.conn.sql("update `tabStock Ledger Entry` set stock_uom = '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.item_code)) # acknowledge user msgprint("Stock Ledger Entries Updated Successfully.") # update item valuation if flt(self.doc.conversion_factor) != flt(1): - wh = sql("select name from `tabWarehouse`") + wh = webnotes.conn.sql("select name from `tabWarehouse`") for w in wh: update_entries_after({"item_code": self.doc.item_code, "warehouse": w[0]}) diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index b23f043a3d..54d0b15836 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -21,7 +21,7 @@ class DocType: def get_bin(self, item_code, warehouse=None): warehouse = warehouse or self.doc.name - bin = sql("select name from tabBin where item_code = %s and \ + bin = webnotes.conn.sql("select name from tabBin where item_code = %s and \ warehouse = %s", (item_code, warehouse)) bin = bin and bin[0][0] or '' if not bin: @@ -163,22 +163,22 @@ class DocType: def on_trash(self): # delete bin - bins = sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1) + bins = webnotes.conn.sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1) for d in bins: if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \ d['indented_qty'] or d['projected_qty'] or d['planned_qty']: msgprint("""Warehouse: %s can not be deleted as qty exists for item: %s""" % (self.doc.name, d['item_code']), raise_exception=1) else: - sql("delete from `tabBin` where name = %s", d['name']) + webnotes.conn.sql("delete from `tabBin` where name = %s", d['name']) # delete cancelled sle - if sql("""select name from `tabStock Ledger Entry` + if webnotes.conn.sql("""select name from `tabStock Ledger Entry` where warehouse = %s and ifnull('is_cancelled', '') = 'No'""", self.doc.name): msgprint("""Warehosue can not be deleted as stock ledger entry exists for this warehouse.""", raise_exception=1) else: - sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name) + webnotes.conn.sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name) def on_rename(self, newdn, olddn, merge=False): if merge: diff --git a/support/doctype/customer_issue/customer_issue.py b/support/doctype/customer_issue/customer_issue.py index 3773cdf360..c099bf699e 100644 --- a/support/doctype/customer_issue/customer_issue.py +++ b/support/doctype/customer_issue/customer_issue.py @@ -27,7 +27,7 @@ class DocType(TransactionBase): self.doc.resolved_by = webnotes.session.user def on_cancel(self): - lst = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t2.prevdoc_docname = '%s' and t1.docstatus!=2"%(self.doc.name)) + lst = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t2.prevdoc_docname = '%s' and t1.docstatus!=2"%(self.doc.name)) if lst: lst1 = ','.join([x[0] for x in lst]) msgprint("Maintenance Visit No. "+lst1+" already created against this customer issue. So can not be Cancelled") diff --git a/support/doctype/maintenance_schedule/maintenance_schedule.py b/support/doctype/maintenance_schedule/maintenance_schedule.py index 4bb121767c..1682da5afa 100644 --- a/support/doctype/maintenance_schedule/maintenance_schedule.py +++ b/support/doctype/maintenance_schedule/maintenance_schedule.py @@ -19,7 +19,7 @@ class DocType(TransactionBase): self.doclist = doclist def get_item_details(self, item_code): - item = sql("select item_name, description from `tabItem` where name = '%s'" %(item_code), as_dict=1) + item = webnotes.conn.sql("select item_name, description from `tabItem` where name = '%s'" %(item_code), as_dict=1) ret = { 'item_name': item and item[0]['item_name'] or '', 'description' : item and item[0]['description'] or '' @@ -29,7 +29,7 @@ class DocType(TransactionBase): def generate_schedule(self): self.doclist = self.doc.clear_table(self.doclist, 'maintenance_schedule_detail') count = 0 - sql("delete from `tabMaintenance Schedule Detail` where parent='%s'" %(self.doc.name)) + webnotes.conn.sql("delete from `tabMaintenance Schedule Detail` where parent='%s'" %(self.doc.name)) for d in getlist(self.doclist, 'item_maintenance_detail'): self.validate_maintenance_detail() s_list =[] @@ -66,7 +66,7 @@ class DocType(TransactionBase): email_map[d.incharge_name] = webnotes.bean("Sales Person", d.incharge_name).run_method("get_email_id") - scheduled_date =sql("select scheduled_date from `tabMaintenance Schedule Detail` \ + scheduled_date =webnotes.conn.sql("select scheduled_date from `tabMaintenance Schedule Detail` \ where incharge_name='%s' and item_code='%s' and parent='%s' " %(d.incharge_name, \ d.item_code, self.doc.name), as_dict=1) @@ -171,7 +171,7 @@ class DocType(TransactionBase): def validate_sales_order(self): for d in getlist(self.doclist, 'item_maintenance_detail'): if d.prevdoc_docname: - chk = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1", d.prevdoc_docname) + chk = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1", d.prevdoc_docname) if chk: msgprint("Maintenance Schedule against "+d.prevdoc_docname+" already exist") raise Exception @@ -185,7 +185,7 @@ class DocType(TransactionBase): cur_s_no = cur_serial_no.split(',') for x in cur_s_no: - chk = sql("select name, status from `tabSerial No` where docstatus!=2 and name=%s", (x)) + chk = webnotes.conn.sql("select name, status from `tabSerial No` where docstatus!=2 and name=%s", (x)) chk1 = chk and chk[0][0] or '' status = chk and chk[0][1] or '' @@ -208,7 +208,7 @@ class DocType(TransactionBase): cur_s_no = cur_serial_no.split(',') for x in cur_s_no: - dt = sql("select delivery_date from `tabSerial No` where name = %s", x) + dt = webnotes.conn.sql("select delivery_date from `tabSerial No` where name = %s", x) dt = dt and dt[0][0] or '' if dt: @@ -224,7 +224,7 @@ class DocType(TransactionBase): cur_s_no = cur_serial_no.split(',') for x in cur_s_no: - sql("update `tabSerial No` set amc_expiry_date = '%s', maintenance_status = 'Under AMC' where name = '%s'"% (amc_end_date,x)) + webnotes.conn.sql("update `tabSerial No` set amc_expiry_date = '%s', maintenance_status = 'Under AMC' where name = '%s'"% (amc_end_date,x)) def on_update(self): webnotes.conn.set(self.doc, 'status', 'Draft') @@ -232,7 +232,7 @@ class DocType(TransactionBase): def validate_serial_no_warranty(self): for d in getlist(self.doclist, 'item_maintenance_detail'): if cstr(d.serial_no).strip(): - dt = sql("""select warranty_expiry_date, amc_expiry_date + dt = webnotes.conn.sql("""select warranty_expiry_date, amc_expiry_date from `tabSerial No` where name = %s""", d.serial_no, as_dict=1) if dt[0]['warranty_expiry_date'] and dt[0]['warranty_expiry_date'] >= d.start_date: webnotes.msgprint("""Serial No: %s is already under warranty upto %s. diff --git a/support/doctype/maintenance_visit/maintenance_visit.py b/support/doctype/maintenance_visit/maintenance_visit.py index dbb2880ac9..60cc3712a6 100644 --- a/support/doctype/maintenance_visit/maintenance_visit.py +++ b/support/doctype/maintenance_visit/maintenance_visit.py @@ -18,7 +18,7 @@ class DocType(TransactionBase): self.doclist = doclist def get_item_details(self, item_code): - item = sql("select item_name,description from `tabItem` where name = '%s'" %(item_code), as_dict=1) + item = webnotes.conn.sql("select item_name,description from `tabItem` where name = '%s'" %(item_code), as_dict=1) ret = { 'item_name' : item and item[0]['item_name'] or '', 'description' : item and item[0]['description'] or '' @@ -27,7 +27,7 @@ class DocType(TransactionBase): def validate_serial_no(self): for d in getlist(self.doclist, 'maintenance_visit_details'): - if d.serial_no and not sql("select name from `tabSerial No` where name = '%s' and docstatus != 2" % d.serial_no): + if d.serial_no and not webnotes.conn.sql("select name from `tabSerial No` where name = '%s' and docstatus != 2" % d.serial_no): msgprint("Serial No: "+ d.serial_no + " not exists in the system") raise Exception @@ -51,7 +51,7 @@ class DocType(TransactionBase): elif self.doc.completion_status == 'Partially Completed': status = 'Work In Progress' else: - nm = sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.doc.name)) + nm = webnotes.conn.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.doc.name)) if nm: status = 'Work In Progress' @@ -64,7 +64,7 @@ class DocType(TransactionBase): service_person = '' work_done = '' - sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname)) + webnotes.conn.sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname)) def check_if_last_visit(self): @@ -76,7 +76,7 @@ class DocType(TransactionBase): check_for_doctype = d.prevdoc_doctype if check_for_docname: - check = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.doc.name, check_for_docname, self.doc.mntc_date, self.doc.mntc_date, self.doc.mntc_time)) + check = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.doc.name, check_for_docname, self.doc.mntc_date, self.doc.mntc_date, self.doc.mntc_time)) if check: check_lst = [x[0] for x in check] diff --git a/utilities/doctype/contact/contact.py b/utilities/doctype/contact/contact.py index 84c8a59de8..58437f1a62 100644 --- a/utilities/doctype/contact/contact.py +++ b/utilities/doctype/contact/contact.py @@ -35,25 +35,24 @@ class DocType(TransactionBase): self.validate_primary_contact() def validate_primary_contact(self): - sql = webnotes.conn.sql if self.doc.is_primary_contact == 1: if self.doc.customer: - sql("update tabContact set is_primary_contact=0 where customer = '%s'" % (self.doc.customer)) + webnotes.conn.sql("update tabContact set is_primary_contact=0 where customer = '%s'" % (self.doc.customer)) elif self.doc.supplier: - sql("update tabContact set is_primary_contact=0 where supplier = '%s'" % (self.doc.supplier)) + webnotes.conn.sql("update tabContact set is_primary_contact=0 where supplier = '%s'" % (self.doc.supplier)) elif self.doc.sales_partner: - sql("update tabContact set is_primary_contact=0 where sales_partner = '%s'" % (self.doc.sales_partner)) + webnotes.conn.sql("update tabContact set is_primary_contact=0 where sales_partner = '%s'" % (self.doc.sales_partner)) else: if self.doc.customer: - if not sql("select name from tabContact where is_primary_contact=1 and customer = '%s'" % (self.doc.customer)): + if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and customer = '%s'" % (self.doc.customer)): self.doc.is_primary_contact = 1 elif self.doc.supplier: - if not sql("select name from tabContact where is_primary_contact=1 and supplier = '%s'" % (self.doc.supplier)): + if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and supplier = '%s'" % (self.doc.supplier)): self.doc.is_primary_contact = 1 elif self.doc.sales_partner: - if not sql("select name from tabContact where is_primary_contact=1 and sales_partner = '%s'" % (self.doc.sales_partner)): + if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and sales_partner = '%s'" % (self.doc.sales_partner)): self.doc.is_primary_contact = 1 def on_trash(self): webnotes.conn.sql("""update `tabSupport Ticket` set contact='' where contact=%s""", - self.doc.name) \ No newline at end of file + self.doc.name) diff --git a/utilities/doctype/sms_control/sms_control.py b/utilities/doctype/sms_control/sms_control.py index d72db529dd..f183920afc 100644 --- a/utilities/doctype/sms_control/sms_control.py +++ b/utilities/doctype/sms_control/sms_control.py @@ -48,7 +48,7 @@ class DocType: def get_contact_number(self, arg): "returns mobile number of the contact" args = load_json(arg) - number = sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" % + number = webnotes.conn.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" % ('%s', args['key'], '%s'), (args['contact_name'], args['value'])) return number and (number[0][0] or number[0][1]) or '' From 16371b721233b0537199373f355851185975fe5b Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 18 Sep 2013 18:31:03 +0530 Subject: [PATCH 005/123] refactor stock ledger to be thread safe --- stock/stock_ledger.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index f0619c7384..0e8a341a4c 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -10,7 +10,9 @@ import json # future reposting class NegativeStockError(webnotes.ValidationError): pass -_exceptions = [] +_exceptions = webnotes.local('stockledger_exceptions') + +# _exceptions = [] def update_entries_after(args, verbose=1): """ update valution rate and qty after transaction @@ -23,8 +25,8 @@ def update_entries_after(args, verbose=1): "posting_time": "12:00" } """ - global _exceptions - _exceptions = [] + if not _exceptions: + webnotes.local.stockledger_exceptions = [] previous_sle = get_sle_before_datetime(args) @@ -140,10 +142,12 @@ def validate_negative_stock(qty_after_transaction, sle): will not consider cancelled entries """ diff = qty_after_transaction + flt(sle.actual_qty) + + if not _exceptions: + webnotes.local.stockledger_exceptions = [] if diff < 0 and abs(diff) > 0.0001: # negative stock! - global _exceptions exc = sle.copy().update({"diff": diff}) _exceptions.append(exc) return False @@ -277,4 +281,4 @@ def get_previous_sle(args, for_update=False): sle = get_stock_ledger_entries(args, ["name != %(sle)s", "timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"], "desc", "limit 1", for_update=for_update) - return sle and sle[0] or {} \ No newline at end of file + return sle and sle[0] or {} From f83576bf9c191c56d05e119013d4fb41dcfabc53 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 18 Sep 2013 18:35:12 +0530 Subject: [PATCH 006/123] [pos] pos.js included in all selling & purchase cycle --- .../purchase_invoice/purchase_invoice.js | 1 + accounts/doctype/sales_invoice/pos.js | 67 +++++++++++-------- accounts/doctype/sales_invoice/pos.py | 15 +++-- .../doctype/sales_invoice/sales_invoice.css | 15 ----- .../doctype/sales_invoice/sales_invoice.js | 1 + .../doctype/purchase_order/purchase_order.js | 1 + .../supplier_quotation/supplier_quotation.js | 1 + public/js/startup.css | 17 +++++ public/js/transaction.js | 7 +- selling/doctype/quotation/quotation.js | 1 + stock/doctype/delivery_note/delivery_note.js | 1 + .../purchase_receipt/purchase_receipt.js | 1 + 12 files changed, 78 insertions(+), 50 deletions(-) delete mode 100644 accounts/doctype/sales_invoice/sales_invoice.css diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js index 2428a7dae9..fb5569a5f0 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -8,6 +8,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details"; wn.provide("erpnext.accounts"); wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js'); wn.require('app/buying/doctype/purchase_common/purchase_common.js'); +wn.require('app/accounts/doctype/sales_invoice/pos.js'); erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ onload: function() { diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 67c4b93186..ee34440b35 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -7,7 +7,7 @@ erpnext.POS = Class.extend({ this.frm = frm; this.wrapper.html('
\
\ -
\ +
\
\
\
\ @@ -88,29 +88,31 @@ erpnext.POS = Class.extend({ }); }, make: function() { - this.make_customer(); + this.make_party(); this.make_item_group(); this.make_search(); this.make_barcode(); this.make_item_list(); }, - make_customer: function() { + make_party: function() { var me = this; - console.log(this.frm); - this.customer = wn.ui.form.make_control({ + this.party = wn.meta.has_field(cur_frm.doc.doctype, "customer") ?"Customer" : "Supplier"; + + this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", - "options": "Customer", - "label": "Customer", - "fieldname": "pos_customer", - "placeholder": "Customer" + "options": this.party, + "label": this.party, + "fieldname": "pos_party", + "placeholder": this.party }, - parent: this.wrapper.find(".customer-area") + parent: this.wrapper.find(".party-area") }); - this.customer.make_input(); - this.customer.$input.on("change", function() { - if(!me.customer.autocomplete_open) - wn.model.set_value(this.frm.doctype, me.frm.docname, "customer", this.value); + this.party_field.make_input(); + this.party_field.$input.on("change", function() { + if(!me.party_field.autocomplete_open) + wn.model.set_value(me.frm.doctype, me.frm.docname, + me.party.toLowerCase(), this.value); }); }, make_item_group: function() { @@ -169,10 +171,17 @@ erpnext.POS = Class.extend({ }, make_item_list: function() { var me = this; + var price_list = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? + this.frm.doc.selling_price_list : this.frm.doc.buying_price_list; + + var sales_or_purchase = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? + "Sales" : "Purchase"; + wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { - price_list: cur_frm.doc.selling_price_list, + sales_or_purchase: sales_or_purchase, + price_list: price_list, item_group: this.item_group.$input.val(), item: this.search.$input.val() }, @@ -203,8 +212,8 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (cur_frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc.customer) { - msgprint("Please select customer first."); + if(!cur_frm.doc[me.party.toLowerCase()]) { + msgprint("Please select " + me.party + " first."); return; } me.add_to_cart($(this).attr("data-item_code")); @@ -222,8 +231,8 @@ erpnext.POS = Class.extend({ // check whether the item is already added if (no_of_items != 0) { - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { if (d.item_code == item_code) caught = true; }); @@ -234,15 +243,16 @@ erpnext.POS = Class.extend({ me.update_qty(item_code, 1); } else { - var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", "entries"); + var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", + this.frm.cscript.fname); child.item_code = item_code; me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); } }, update_qty: function(item_code, qty, textbox_qty) { var me = this; - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { if (d.item_code == item_code) { if (textbox_qty) { if (qty == 0 && d.item_code == item_code) @@ -260,14 +270,14 @@ erpnext.POS = Class.extend({ }, refresh: function() { var me = this; - this.customer.set_input(this.frm.doc.customer); + this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]); this.barcode.set_input(""); // add items var $items = me.wrapper.find("#cart tbody").empty(); - $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, "entries", - this.frm.doctype), function(i, d) { + $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, + this.frm.cscript.fname, this.frm.doctype), function(i, d) { $(repl('\ %(item_code)s%(item_name)s\ Date: Wed, 18 Sep 2013 18:35:47 +0530 Subject: [PATCH 007/123] refactor newsletter for naming_series global --- support/doctype/newsletter/newsletter.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/support/doctype/newsletter/newsletter.py b/support/doctype/newsletter/newsletter.py index b201cc5586..9a27d839f8 100644 --- a/support/doctype/newsletter/newsletter.py +++ b/support/doctype/newsletter/newsletter.py @@ -105,7 +105,6 @@ def get_lead_options(): } -lead_naming_series = None def create_lead(email_id): """create a lead if it does not exist""" from email.utils import parseaddr @@ -119,7 +118,7 @@ def create_lead(email_id): "email_id": email_id, "lead_name": real_name or email_id, "status": "Contacted", - "naming_series": lead_naming_series or get_lead_naming_series(), + "naming_series": get_lead_naming_series(), "company": webnotes.conn.get_default("company"), "source": "Email" }) @@ -127,7 +126,7 @@ def create_lead(email_id): def get_lead_naming_series(): """gets lead's default naming series""" - global lead_naming_series + lead_naming_series = None naming_series_field = webnotes.get_doctype("Lead").get_field("naming_series") if naming_series_field.default: lead_naming_series = naming_series_field.default From 7782e83d33c1f39fe0c54d92fed57508528d6a66 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 18 Sep 2013 18:52:10 +0530 Subject: [PATCH 008/123] refactor upload attendance for doclist global --- hr/doctype/upload_attendance/upload_attendance.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hr/doctype/upload_attendance/upload_attendance.py b/hr/doctype/upload_attendance/upload_attendance.py index c1344b90e4..5e2b02ea1f 100644 --- a/hr/doctype/upload_attendance/upload_attendance.py +++ b/hr/doctype/upload_attendance/upload_attendance.py @@ -9,7 +9,8 @@ from webnotes.utils import cstr, add_days, date_diff from webnotes import msgprint, _ from webnotes.utils.datautils import UnicodeWriter -doclist = None +# doclist = None +doclist = webnotes.local('uploadattendance_doclist') class DocType(): def __init__(self, doc, doclist=[]): @@ -22,8 +23,7 @@ def get_template(): raise webnotes.PermissionError args = webnotes.form_dict - global doclist - doclist = webnotes.model.doctype.get("Attendance") + webnotes.local.uploadattendance_doclist = webnotes.model.doctype.get("Attendance") w = UnicodeWriter() w = add_header(w) @@ -144,4 +144,4 @@ def upload(): webnotes.conn.rollback() else: webnotes.conn.commit() - return {"messages": ret, "error": error} \ No newline at end of file + return {"messages": ret, "error": error} From 4259f7278a81f4eb88ee07ee377442c62f2a4719 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Thu, 19 Sep 2013 16:14:16 +0530 Subject: [PATCH 009/123] [fix] set qty=1 for all purchase cycle --- buying/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buying/utils.py b/buying/utils.py index f4fb2f3ff8..179db9bf46 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean): out = webnotes._dict({ "description": item.description_html or item.description, - "qty": 0.0, + "qty": 1.0, "uom": item.stock_uom, "conversion_factor": 1.0, "warehouse": args.warehouse or item.default_warehouse, From e9470815523489006445247435cc24eb350a9757 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Thu, 19 Sep 2013 19:09:15 +0530 Subject: [PATCH 010/123] [pos] pos view in all sales & purchase cycle finished --- accounts/doctype/sales_invoice/pos.js | 71 +++++++++++-------- .../doctype/sales_invoice/sales_invoice.txt | 5 +- buying/utils.py | 2 +- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index ee34440b35..c76db1394f 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -71,7 +71,18 @@ erpnext.POS = Class.extend({
\
\ '); - + + if (wn.meta.has_field(cur_frm.doc.doctype, "customer")) { + this.party = "Customer"; + this.price_list = this.frm.doc.selling_price_list; + this.sales_or_purchase = "Sales"; + } + else if (wn.meta.has_field(cur_frm.doc.doctype, "supplier")) { + this.party = "Supplier"; + this.price_list = this.frm.doc.buying_price_list; + this.sales_or_purchase = "Purchase"; + } + this.make(); var me = this; @@ -95,9 +106,7 @@ erpnext.POS = Class.extend({ this.make_item_list(); }, make_party: function() { - var me = this; - this.party = wn.meta.has_field(cur_frm.doc.doctype, "customer") ?"Customer" : "Supplier"; - + var me = this; this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -170,18 +179,12 @@ erpnext.POS = Class.extend({ }); }, make_item_list: function() { - var me = this; - var price_list = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? - this.frm.doc.selling_price_list : this.frm.doc.buying_price_list; - - var sales_or_purchase = wn.meta.has_field(this.frm.doc.doctype, "selling_price_list") ? - "Sales" : "Purchase"; - + var me = this; wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { - sales_or_purchase: sales_or_purchase, - price_list: price_list, + sales_or_purchase: this.sales_or_purchase, + price_list: this.price_list, item_group: this.item_group.$input.val(), item: this.search.$input.val() }, @@ -216,7 +219,8 @@ erpnext.POS = Class.extend({ msgprint("Please select " + me.party + " first."); return; } - me.add_to_cart($(this).attr("data-item_code")); + else + me.add_to_cart($(this).attr("data-item_code")); }); } } @@ -227,8 +231,8 @@ erpnext.POS = Class.extend({ var caught = false; // get no_of_items - no_of_items = me.wrapper.find("#cart tbody").length; - + var no_of_items = me.wrapper.find("#cart tbody tr").length; + // check whether the item is already added if (no_of_items != 0) { $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, @@ -288,15 +292,15 @@ erpnext.POS = Class.extend({ item_code: d.item_code, item_name: d.item_name===d.item_code ? "" : ("
" + d.item_name), qty: d.qty, - rate: format_currency(d.ref_rate, cur_frm.doc.price_list_currency), - amount: format_currency(d.export_amount, cur_frm.doc.price_list_currency) + rate: format_currency(d.ref_rate, cur_frm.doc.currency), + amount: format_currency(d.export_amount, cur_frm.doc.currency) } )).appendTo($items); }); // taxes - var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges", - this.frm.doctype); + var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges", + this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype); $(".tax-table") .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); @@ -308,15 +312,15 @@ erpnext.POS = Class.extend({ ', { description: d.description, rate: d.rate, - tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency) + tax_amount: format_currency(d.tax_amount, me.frm.doc.currency) })).appendTo(".tax-table tbody"); }); // set totals this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, - cur_frm.doc.price_list_currency)); + cur_frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.price_list_currency)); + cur_frm.doc.currency)); // if form is local then only run all these functions if (cur_frm.doc.docstatus===0) { @@ -331,7 +335,7 @@ erpnext.POS = Class.extend({ }); // on td click toggle the highlighting of row - $("#cart tbody tr td").on("click", function() { + me.wrapper.find("#cart tbody tr td").on("click", function() { var row = $(this).closest("tr"); if (row.attr("data-selected") == "false") { row.attr("class", "warning"); @@ -345,18 +349,26 @@ erpnext.POS = Class.extend({ }); + this.make_item_list(); me.refresh_delete_btn(); cur_frm.pos.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons - if (cur_frm.doc.docstatus>=1 && cint(cur_frm.doc.is_pos)) { + if (cur_frm.doc.docstatus>=1) { me.wrapper.find('input, button').each(function () { $(this).prop('disabled', true); }); $(".delete-items").hide(); $(".make-payment").hide(); } + + // Show Make Payment button only in Sales Invoice + if (this.frm.doctype != "Sales Invoice") + $(".make-payment").hide(); + + if (this.frm.doctype == "Quotation") + $(".party-area").toggle(cur_frm.doc.quotation_to=="Customer" ? true : false) }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); @@ -381,16 +393,17 @@ erpnext.POS = Class.extend({ remove_selected_item: function() { var me = this; var selected_items = []; - var no_of_items = $("#cart tbody tr").length; + var no_of_items = me.wrapper.find("#cart tbody tr").length; for(var x=0; x<=no_of_items - 1; x++) { - var row = $("#cart tbody tr:eq(" + x + ")"); + var row = me.wrapper.find("#cart tbody tr:eq(" + x + ")"); if(row.attr("data-selected") == "true") { selected_items.push(row.attr("id")); } } - + var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, this.frm.cscript.fname, this.frm.doctype); + $.each(child, function(i, d) { for (var i in selected_items) { if (d.item_code == selected_items[i]) { @@ -405,7 +418,7 @@ erpnext.POS = Class.extend({ }, make_payment: function() { var me = this; - var no_of_items = $("#cart tbody tr").length; + var no_of_items = me.wrapper.find("#cart tbody tr").length; var mode_of_payment = []; if (no_of_items == 0) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index f921f24223..00c6c2cc5c 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-09-01 05:26:13", + "modified": "2013-09-19 11:42:13", "modified_by": "Administrator", "owner": "Administrator" }, @@ -180,6 +180,7 @@ "search_index": 1 }, { + "default": "Today", "description": "Enter the date by which payments from customer is expected against this invoice.", "doctype": "DocField", "fieldname": "due_date", @@ -411,7 +412,7 @@ "doctype": "DocField", "fieldname": "other_charges", "fieldtype": "Table", - "label": "Taxes and Charges1", + "label": "Sales Taxes and Charges", "oldfieldname": "other_charges", "oldfieldtype": "Table", "options": "Sales Taxes and Charges", diff --git a/buying/utils.py b/buying/utils.py index f4fb2f3ff8..179db9bf46 100644 --- a/buying/utils.py +++ b/buying/utils.py @@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean): out = webnotes._dict({ "description": item.description_html or item.description, - "qty": 0.0, + "qty": 1.0, "uom": item.stock_uom, "conversion_factor": 1.0, "warehouse": args.warehouse or item.default_warehouse, From cfed8c44b4a0f699c6e00f11f47cb70ecf324b5c Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Sat, 21 Sep 2013 15:16:47 +0530 Subject: [PATCH 011/123] conf migration --- setup/doctype/backup_manager/backup_googledrive.py | 4 ++-- setup/doctype/email_digest/email_digest.py | 2 +- startup/boot.py | 4 ++-- startup/event_handlers.py | 4 ++-- support/doctype/newsletter/newsletter.py | 2 +- utilities/demo/demo_control_panel.py | 4 ++-- utilities/demo/make_demo.py | 4 ++-- utilities/demo/make_erpnext_demo.py | 4 ++-- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index 5d7b6ad0fa..ee795186da 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -113,7 +113,7 @@ def backup_to_gdrive(): def get_gdrive_flow(): from oauth2client.client import OAuth2WebServerFlow - import conf + from webnotes import conf if not hasattr(conf, "gdrive_client_id"): webnotes.msgprint(_("Please set Google Drive access keys in") + " conf.py", @@ -169,4 +169,4 @@ def create_folder(name, service, folder_id): return database['id'] if __name__=="__main__": - backup_to_gdrive() \ No newline at end of file + backup_to_gdrive() diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py index 39e377a601..2a9acaa8b9 100644 --- a/setup/doctype/email_digest/email_digest.py +++ b/setup/doctype/email_digest/email_digest.py @@ -457,7 +457,7 @@ def send(): from webnotes.utils import getdate now_date = now_datetime().date() - import conf + from webnotes import conf if hasattr(conf, "expires_on") and now_date > getdate(conf.expires_on): # do not send email digests to expired accounts return diff --git a/startup/boot.py b/startup/boot.py index 886b805db4..20887f720c 100644 --- a/startup/boot.py +++ b/startup/boot.py @@ -32,7 +32,7 @@ def boot_session(bootinfo): # load subscription info - import conf + from webnotes import conf for key in ['max_users', 'expires_on', 'max_space', 'status', 'commercial_support']: if hasattr(conf, key): bootinfo[key] = getattr(conf, key) @@ -53,4 +53,4 @@ def get_letter_heads(): ret = webnotes.conn.sql("""select name, content from `tabLetter Head` where ifnull(disabled,0)=0""") return dict(ret) - \ No newline at end of file + diff --git a/startup/event_handlers.py b/startup/event_handlers.py index 57345f3ca0..a333857b1b 100644 --- a/startup/event_handlers.py +++ b/startup/event_handlers.py @@ -39,7 +39,7 @@ def on_logout(login_manager): def check_if_expired(): """check if account is expired. If expired, do not allow login""" - import conf + from webnotes import conf # check if expires_on is specified if not hasattr(conf, 'expires_on'): return @@ -75,4 +75,4 @@ def comment_added(doc): """add comment to feed""" home.make_feed('Comment', doc.comment_doctype, doc.comment_docname, doc.comment_by, '"' + doc.comment + '"', '#6B24B3') - \ No newline at end of file + diff --git a/support/doctype/newsletter/newsletter.py b/support/doctype/newsletter/newsletter.py index 9a27d839f8..13ad47a0d8 100644 --- a/support/doctype/newsletter/newsletter.py +++ b/support/doctype/newsletter/newsletter.py @@ -90,7 +90,7 @@ class DocType(): webnotes.msgprint(_("""Please save the Newsletter before sending."""), raise_exception=1) - import conf + from webnotes import conf if getattr(conf, "status", None) == "Trial": webnotes.msgprint(_("""Sending newsletters is not allowed for Trial users, \ to prevent abuse of this feature."""), raise_exception=1) diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py index 1f381d5eb6..1da690245c 100644 --- a/utilities/demo/demo_control_panel.py +++ b/utilities/demo/demo_control_panel.py @@ -1,7 +1,7 @@ def on_login(self): from webnotes.utils import validate_email_add - import conf + from webnotes import conf if hasattr(conf, "demo_notify_url"): if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email): import requests @@ -10,4 +10,4 @@ "subject":"Logged into Demo", "sender": webnotes.form_dict.lead_email, "message": "via demo.erpnext.com" - }) \ No newline at end of file + }) diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index a526c2a301..883186791a 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -355,7 +355,7 @@ def how_many(doctype): def install(): print "Creating Fresh Database..." from webnotes.install_lib.install import Installer - import conf + from webnotes import conf inst = Installer('root') inst.import_from_db(conf.demo_db_name, verbose = 1) @@ -414,4 +414,4 @@ def import_data(dt, submit=False, overwrite=False): if submit: webnotes.form_dict["params"] = json.dumps({"_submit": 1}) webnotes.uploaded_file = os.path.join(os.path.dirname(__file__), "demo_docs", doctype+".csv") - upload(overwrite=overwrite) \ No newline at end of file + upload(overwrite=overwrite) diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 766da2612f..70e7322ea8 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -42,7 +42,7 @@ def make_demo_user(): p.doc.last_name = "User" p.doc.enabled = 1 p.doc.user_type = "ERPNext Demo" - p.doc.send_invite_email = 0 + # p.doc.send_invite_email = 0 p.doc.new_password = "demo" p.insert() add_roles(p) @@ -118,4 +118,4 @@ def make_demo_on_login_script(): webnotes.conn.commit() if __name__=="__main__": - make_demo_app() \ No newline at end of file + make_demo_app() From f624ffa40abcf5aca9c4d0c6295f5bb00c856ca9 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 23 Sep 2013 12:27:16 +0530 Subject: [PATCH 012/123] [pos] refresh() to be called at minimum --- accounts/doctype/sales_invoice/pos.js | 8 +-- .../doctype/sales_invoice/sales_invoice.js | 50 +------------------ public/js/transaction.js | 2 +- 3 files changed, 6 insertions(+), 54 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index c76db1394f..4ef239744b 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -106,7 +106,7 @@ erpnext.POS = Class.extend({ this.make_item_list(); }, make_party: function() { - var me = this; + var me = this; this.party_field = wn.ui.form.make_control({ df: { "fieldtype": "Link", @@ -179,7 +179,7 @@ erpnext.POS = Class.extend({ }); }, make_item_list: function() { - var me = this; + var me = this; wn.call({ method: 'accounts.doctype.sales_invoice.pos.get_items', args: { @@ -349,7 +349,6 @@ erpnext.POS = Class.extend({ }); - this.make_item_list(); me.refresh_delete_btn(); cur_frm.pos.barcode.$input.focus(); } @@ -368,7 +367,8 @@ erpnext.POS = Class.extend({ $(".make-payment").hide(); if (this.frm.doctype == "Quotation") - $(".party-area").toggle(cur_frm.doc.quotation_to=="Customer" ? true : false) + if (cur_frm.doc.quotation_to=="Customer") + this.party_field.remove(); }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index e07ed2816d..13cbc634dd 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -121,54 +121,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); }); }, - - // pos_btn: function() { - // if(cur_frm.$pos_btn) - // cur_frm.$pos_btn.remove(); - - // if(!cur_frm.pos_active) { - // var btn_label = wn._("POS View"), - // icon = "icon-desktop"; - - // cur_frm.cscript.sales_order_btn(); - // cur_frm.cscript.delivery_note_btn(); - // } else { - // var btn_label = wn._("Invoice View"), - // icon = "icon-file-text"; - - // if (cur_frm.doc.docstatus===0) { - // this.$delivery_note_btn.remove(); - // this.$sales_order_btn.remove(); - // } - // } - - // cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() { - // cur_frm.cscript.toggle_pos(); - // cur_frm.cscript.pos_btn(); - // }, icon); - // }, - - // toggle_pos: function(show) { - // if (!this.frm.doc.selling_price_list) - // msgprint(wn._("Please select Price List")) - // else { - // if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return; - - // // make pos - // if(!cur_frm.pos) { - // cur_frm.layout.add_view("pos"); - // cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm); - // } - - // // toggle view - // cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos"); - // cur_frm.pos_active = !cur_frm.pos_active; - - // // refresh - // if(cur_frm.pos_active) - // cur_frm.pos.refresh(); - // } - // }, tc_name: function() { this.get_terms(); @@ -176,7 +128,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte is_pos: function() { cur_frm.cscript.hide_fields(this.frm.doc); - if(cint(this.frm.doc.is_pos)) { if(!this.frm.doc.company) { this.frm.set_value("is_pos", 0); @@ -194,6 +145,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); } } + }, debit_to: function() { diff --git a/public/js/transaction.js b/public/js/transaction.js index a38e3a777c..1a1c98ca6b 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -98,7 +98,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ if((show===true && this.pos_active) || (show===false && !this.pos_active)) return; // make pos - if(!this.pos) { + if(!this.frm.pos) { this.frm.layout.add_view("pos"); this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm); } From 0eb811a51808b1c7aaae1a3dd8135424f70a972f Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 23 Sep 2013 16:04:50 +0530 Subject: [PATCH 013/123] [minor] remove send_invite_email field from demo docs --- utilities/demo/demo_docs/Profile.csv | 80 ++++++++++++++-------------- utilities/demo/make_erpnext_demo.py | 2 - 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/utilities/demo/demo_docs/Profile.csv b/utilities/demo/demo_docs/Profile.csv index 2e7a2cee15..eb456c16ad 100644 --- a/utilities/demo/demo_docs/Profile.csv +++ b/utilities/demo/demo_docs/Profile.csv @@ -1,40 +1,40 @@ -Data Import Template,,,,,,,,,,,,,,,,,,,,, -Table:,Profile,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,, -Notes:,,,,,,,,,,,,,,,,,,,,, -Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,, -First data column must be blank.,,,,,,,,,,,,,,,,,,,,, -"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,, -"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,, -Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,, -"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,, -You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,, -DocType:,Profile,,,,,,,,,,,,,,,,,,,, -Column Labels:,ID,Email,First Name,User Type,Enabled,Middle Name (Optional),Last Name,Send Invite Email,Language,Birth Date,Gender,New Password,User Image,Background Image,Bio,Email Signature,Login After,Login Before,Restrict IP,Last Login,Last IP -Column Name:,name,email,first_name,user_type,enabled,middle_name,last_name,send_invite_email,language,birth_date,gender,new_password,user_image,background_image,bio,email_signature,login_after,login_before,restrict_ip,last_login,last_ip -Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No -Type:,Data (text),Data,Data,Select,Check,Data,Data,Check,Select,Date,Select,Password,Select,Select,Small Text,Small Text,Int,Int,Data,Read Only,Read Only -Info:,,,,"One of: System User, Website User",0 or 1,,,0 or 1,"One of: العربية, Deutsch, english, español, français, हिंदी, Hrvatski, nederlands, português, português brasileiro, српски, தமிழ், ไทย",,"One of: Male, Female, Other",,One of: attach_files:,One of: attach_files:,,,Integer,Integer,,, -Start entering data below this line,,,,,,,,,,,,,,,,,,,,, -,,DikmanShervashidze@armyspy.com,Dikman,System User,1,V,Shervashidze,0,,,,testpass,,,,,,,,, -,,Zukutakitoteka@teleworm.us,Zukutakitoteka,System User,1,,,0,,,,testpass,,,,,,,,, -,,HatsueKashiwagi@cuvox.de,Hatsue,System User,1,H,Kashiwagi,0,,,,testpass,,,,,,,,, -,,NuranVerkleij@einrot.com,Nuran,System User,1,T,Verkleij,0,,,,testpass,,,,,,,,, -,,aromn@armyspy.com,Дмитрий,System User,1,З,Пирогов,0,,,,testpass,,,,,,,,, -,,TildeLindqvist@cuvox.de,Tilde,System User,1,T,Lindqvist,0,,,,testpass,,,,,,,,, -,,MichalSobczak@teleworm.us,Michał,System User,1,S,Sobczak,0,,,,testpass,,,,,,,,, -,,GabrielleLoftus@superrito.com,Gabrielle,System User,1,J,Loftus,0,,,,testpass,,,,,,,,, -,,VakhitaRyzaev@teleworm.us,Vakhita,System User,1,A,Ryzaev,0,,,,testpass,,,,,,,,, -,,CharmaineGaudreau@cuvox.de,Charmaine,System User,1,D,Gaudreau,0,,,,testpass,,,,,,,,, -,,RafaelaMaartens@cuvox.de,Rafaëla,System User,1,Z,Maartens,0,,,,testpass,,,,,,,,, -,,NuguseYohannes@dayrep.com,Nuguse,System User,0,S,Yohannes,0,,,,testpass,,,,,,,,, -,,panca@armyspy.com,Раиса,System User,0,В,Белякова,0,,,,testpass,,,,,,,,, -,,CaYinLong@gustr.com,胤隆,System User,1,婷,蔡,0,,,,testpass,,,,,,,,, -,,FreddieScott@armyspy.com,Freddie,System User,1,A,Scott,0,,,,testpass,,,,,,,,, -,,BergoraVigfusdottir@superrito.com,Bergþóra,System User,1,Ö,Vigfúsdóttir,0,,,,testpass,,,,,,,,, -,,WardNajmalDinKalb@cuvox.de,Ward,System User,1,N,Kalb,0,,,,testpass,,,,,,,,, -,,WanMai@teleworm.us,Wan,System User,1,A,Mai,0,,,,testpass,,,,,,,,, -,,LeonAbdulov@superrito.com,Leon,System User,1,A,Abdulov,0,,,,testpass,,,,,,,,, -,,SabinaNovotna@superrito.com,Sabina,System User,1,J,Novotná,0,,,,testpass,,,,,,,,, \ No newline at end of file +Data Import Template,,,,,,,,,,,,,,,,,,,, +Table:,Profile,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,, +Notes:,,,,,,,,,,,,,,,,,,,, +Please do not change the template headings.,,,,,,,,,,,,,,,,,,,, +First data column must be blank.,,,,,,,,,,,,,,,,,,,, +"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,, +"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,, +Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,, +"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,, +You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,, +DocType:,Profile,,,,,,,,,,,,,,,,,,, +Column Labels:,ID,Email,First Name,User Type,Enabled,Middle Name (Optional),Last Name,Language,Birth Date,Gender,New Password,User Image,Background Image,Bio,Email Signature,Login After,Login Before,Restrict IP,Last Login,Last IP +Column Name:,name,email,first_name,user_type,enabled,middle_name,last_name,language,birth_date,gender,new_password,user_image,background_image,bio,email_signature,login_after,login_before,restrict_ip,last_login,last_ip +Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No +Type:,Data (text),Data,Data,Select,Check,Data,Data,Select,Date,Select,Password,Select,Select,Small Text,Small Text,Int,Int,Data,Read Only,Read Only +Info:,,,,"One of: System User, Website User",0 or 1,,,"One of: العربية, Deutsch, english, español, français, हिंदी, Hrvatski, nederlands, português, português brasileiro, српски, தமிழ், ไทย",,"One of: Male, Female, Other",,One of: attach_files:,One of: attach_files:,,,Integer,Integer,,, +Start entering data below this line,,,,,,,,,,,,,,,,,,,, +,,DikmanShervashidze@armyspy.com,Dikman,System User,1,V,Shervashidze,,,,testpass,,,,,,,,, +,,Zukutakitoteka@teleworm.us,Zukutakitoteka,System User,1,,,,,,testpass,,,,,,,,, +,,HatsueKashiwagi@cuvox.de,Hatsue,System User,1,H,Kashiwagi,,,,testpass,,,,,,,,, +,,NuranVerkleij@einrot.com,Nuran,System User,1,T,Verkleij,,,,testpass,,,,,,,,, +,,aromn@armyspy.com,Дмитрий,System User,1,З,Пирогов,,,,testpass,,,,,,,,, +,,TildeLindqvist@cuvox.de,Tilde,System User,1,T,Lindqvist,,,,testpass,,,,,,,,, +,,MichalSobczak@teleworm.us,Michał,System User,1,S,Sobczak,,,,testpass,,,,,,,,, +,,GabrielleLoftus@superrito.com,Gabrielle,System User,1,J,Loftus,,,,testpass,,,,,,,,, +,,VakhitaRyzaev@teleworm.us,Vakhita,System User,1,A,Ryzaev,,,,testpass,,,,,,,,, +,,CharmaineGaudreau@cuvox.de,Charmaine,System User,1,D,Gaudreau,,,,testpass,,,,,,,,, +,,RafaelaMaartens@cuvox.de,Rafaëla,System User,1,Z,Maartens,,,,testpass,,,,,,,,, +,,NuguseYohannes@dayrep.com,Nuguse,System User,0,S,Yohannes,,,,testpass,,,,,,,,, +,,panca@armyspy.com,Раиса,System User,0,В,Белякова,,,,testpass,,,,,,,,, +,,CaYinLong@gustr.com,胤隆,System User,1,婷,蔡,,,,testpass,,,,,,,,, +,,FreddieScott@armyspy.com,Freddie,System User,1,A,Scott,,,,testpass,,,,,,,,, +,,BergoraVigfusdottir@superrito.com,Bergþóra,System User,1,Ö,Vigfúsdóttir,,,,testpass,,,,,,,,, +,,WardNajmalDinKalb@cuvox.de,Ward,System User,1,N,Kalb,,,,testpass,,,,,,,,, +,,WanMai@teleworm.us,Wan,System User,1,A,Mai,,,,testpass,,,,,,,,, +,,LeonAbdulov@superrito.com,Leon,System User,1,A,Abdulov,,,,testpass,,,,,,,,, +,,SabinaNovotna@superrito.com,Sabina,System User,1,J,Novotná,,,,testpass,,,,,,,,, diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 70e7322ea8..6426367a95 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -42,7 +42,6 @@ def make_demo_user(): p.doc.last_name = "User" p.doc.enabled = 1 p.doc.user_type = "ERPNext Demo" - # p.doc.send_invite_email = 0 p.doc.new_password = "demo" p.insert() add_roles(p) @@ -58,7 +57,6 @@ def make_demo_user(): p.doc.last_name = "User" p.doc.enabled = 1 p.doc.user_type = "System User" - p.doc.send_invite_email = 0 p.doc.new_password = "admin010123" p.insert() roles.append("System Manager") From 1e15fe1ade79f376cc5aa2b17b59d59bbbdda8cf Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 23 Sep 2013 16:07:42 +0530 Subject: [PATCH 014/123] [fix] [minor] toggle display warehouse column based on update_stock --- accounts/doctype/sales_invoice/sales_invoice.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 60f73b5a19..0aa85e2ae8 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -256,7 +256,6 @@ cur_frm.cscript.hide_fields = function(doc) { 'total_commission', 'advances']; item_flds_normal = ['sales_order', 'delivery_note'] - item_flds_pos = ['serial_no', 'batch_no', 'actual_qty', 'expense_account'] if(cint(doc.is_pos) == 1) { hide_field(par_flds); @@ -271,7 +270,9 @@ cur_frm.cscript.hide_fields = function(doc) { cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_normal, true); } - cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_pos, (cint(doc.update_stock)==1?true:false)); + item_flds_stock = ['serial_no', 'batch_no', 'actual_qty', 'expense_account', 'warehouse'] + cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_stock, + (cint(doc.update_stock)==1 ? true : false)); // India related fields var cp = wn.control_panel; From ac030a57c2fc568563f070c572dda1834f66a7b9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 23 Sep 2013 16:27:18 +0530 Subject: [PATCH 015/123] [minor] [cleanup] removed banner from lead --- selling/doctype/lead/lead.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/selling/doctype/lead/lead.js b/selling/doctype/lead/lead.js index a3ae783867..aadc091da9 100644 --- a/selling/doctype/lead/lead.js +++ b/selling/doctype/lead/lead.js @@ -34,15 +34,6 @@ erpnext.LeadController = wn.ui.form.Controller.extend({ erpnext.hide_naming_series(); this.frm.clear_custom_buttons(); - this.frm.dashboard.reset(doc); - if(!doc.__islocal) { - if(doc.status=="Converted") { - this.frm.dashboard.set_headline_alert(wn._("Converted"), "alert-success", "icon-ok-sign"); - } else { - this.frm.dashboard.set_headline_alert(wn._(doc.status), "alert-info", "icon-exclamation-sign"); - } - } - this.frm.__is_customer = this.frm.__is_customer || this.frm.doc.__is_customer; if(!this.frm.doc.__islocal && !this.frm.__is_customer) { this.frm.add_custom_button("Create Customer", this.create_customer); From be68542bab85e3e0aaf7c4ea7fc04197777b2faf Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 23 Sep 2013 18:34:13 +0530 Subject: [PATCH 016/123] [minor] fetch debit/credit based on against JV --- .../journal_voucher/journal_voucher.js | 62 +++++++++++++------ .../journal_voucher/journal_voucher.py | 38 +++++++++--- .../doctype/support_ticket/support_ticket.js | 4 +- 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/accounts/doctype/journal_voucher/journal_voucher.js b/accounts/doctype/journal_voucher/journal_voucher.js index a3aa6f127a..a6aa007b12 100644 --- a/accounts/doctype/journal_voucher/journal_voucher.js +++ b/accounts/doctype/journal_voucher/journal_voucher.js @@ -59,6 +59,50 @@ erpnext.accounts.JournalVoucher = wn.ui.form.Controller.extend({ }; }); }, + + against_voucher: function(doc, cdt, cdn) { + var d = wn.model.get_doc(cdt, cdn); + if (d.against_voucher && !flt(d.debit)) { + this.get_outstanding({ + 'doctype': 'Purchase Invoice', + 'docname': d.against_voucher + }, d) + } + }, + + against_invoice: function(doc, cdt, cdn) { + var d = wn.model.get_doc(cdt, cdn); + if (d.against_invoice && !flt(d.credit)) { + this.get_outstanding({ + 'doctype': 'Sales Invoice', + 'docname': d.against_invoice + }, d) + } + }, + + against_jv: function(doc, cdt, cdn) { + var d = wn.model.get_doc(cdt, cdn); + if (d.against_jv && !flt(d.credit) && !flt(d.debit)) { + this.get_outstanding({ + 'doctype': 'Journal Voucher', + 'docname': d.against_jv, + 'account': d.account + }, d) + } + }, + + get_outstanding: function(args, child) { + var me = this; + return this.frm.call({ + child: child, + method: "get_outstanding", + args: { args: args}, + callback: function(r) { + cur_frm.cscript.update_totals(me.frm.doc); + } + }); + } + }); cur_frm.script_manager.make(erpnext.accounts.JournalVoucher); @@ -88,24 +132,6 @@ cur_frm.cscript.is_opening = function(doc, cdt, cdn) { if (doc.is_opening == 'Yes') unhide_field('aging_date'); } -cur_frm.cscript.against_voucher = function(doc,cdt,cdn) { - var d = locals[cdt][cdn]; - if (d.against_voucher && !flt(d.debit)) { - args = {'doctype': 'Purchase Invoice', 'docname': d.against_voucher } - return get_server_fields('get_outstanding',docstring(args),'entries',doc,cdt,cdn,1,function(r,rt) { cur_frm.cscript.update_totals(doc); }); - } -} - -cur_frm.cscript.against_invoice = function(doc,cdt,cdn) { - var d = locals[cdt][cdn]; - if (d.against_invoice && !flt(d.credit)) { - args = {'doctype': 'Sales Invoice', 'docname': d.against_invoice } - return get_server_fields('get_outstanding',docstring(args),'entries',doc,cdt,cdn,1,function(r,rt) { cur_frm.cscript.update_totals(doc); }); - } -} - -// Update Totals - cur_frm.cscript.update_totals = function(doc) { var td=0.0; var tc =0.0; var el = getchildren('Journal Voucher Detail', doc.name, 'entries'); diff --git a/accounts/doctype/journal_voucher/journal_voucher.py b/accounts/doctype/journal_voucher/journal_voucher.py index a43f8ca7a5..a87166c3c2 100644 --- a/accounts/doctype/journal_voucher/journal_voucher.py +++ b/accounts/doctype/journal_voucher/journal_voucher.py @@ -260,15 +260,6 @@ class DocType(AccountsController): if gl_map: make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj) - def get_outstanding(self, args): - args = eval(args) - o_s = webnotes.conn.sql("""select outstanding_amount from `tab%s` where name = %s""" % - (args['doctype'], '%s'), args['docname']) - if args['doctype'] == 'Purchase Invoice': - return {'debit': o_s and flt(o_s[0][0]) or 0} - if args['doctype'] == 'Sales Invoice': - return {'credit': o_s and flt(o_s[0][0]) or 0} - def get_balance(self): if not getlist(self.doclist,'entries'): msgprint("Please enter atleast 1 entry in 'GL Entries' table") @@ -434,4 +425,31 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters): where jv_detail.parent = jv.name and jv_detail.account = %s and jv.docstatus = 1 and jv.%s like %s order by jv.name desc limit %s, %s""" % ("%s", searchfield, "%s", "%s", "%s"), - (filters["account"], "%%%s%%" % txt, start, page_len)) \ No newline at end of file + (filters["account"], "%%%s%%" % txt, start, page_len)) + +@webnotes.whitelist() +def get_outstanding(args): + args = eval(args) + if args.get("doctype") == "Journal Voucher" and args.get("account"): + against_jv_amount = webnotes.conn.sql(""" + select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) + from `tabJournal Voucher Detail` where parent=%s and account=%s + and ifnull(against_invoice, '')='' and ifnull(against_voucher, '')='' + and ifnull(against_jv, '')=''""", (args['docname'], args['account'])) + + against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0 + if against_jv_amount > 0: + return {"credit": against_jv_amount} + else: + return {"debit": -1* against_jv_amount} + + elif args.get("doctype") == "Sales Invoice": + return { + "credit": flt(webnotes.conn.get_value("Sales Invoice", args["docname"], + "outstanding_amount")) + } + elif args.get("doctype") == "Purchase Invoice": + return { + "debit": flt(webnotes.conn.get_value("Purchase Invoice", args["docname"], + "outstanding_amount")) + } \ No newline at end of file diff --git a/support/doctype/support_ticket/support_ticket.js b/support/doctype/support_ticket/support_ticket.js index 0e61273439..c61d9732f8 100644 --- a/support/doctype/support_ticket/support_ticket.js +++ b/support/doctype/support_ticket/support_ticket.js @@ -6,7 +6,7 @@ cur_frm.fields_dict.customer.get_query = function(doc,cdt,cdn) { wn.provide("erpnext.support"); // TODO commonify this code -erpnext.support.CustomerIssue = wn.ui.form.Controller.extend({ +erpnext.support.SupportTicket = wn.ui.form.Controller.extend({ customer: function() { var me = this; if(this.frm.doc.customer) { @@ -18,7 +18,7 @@ erpnext.support.CustomerIssue = wn.ui.form.Controller.extend({ } }); -$.extend(cur_frm.cscript, new erpnext.support.CustomerIssue({frm: cur_frm})); +$.extend(cur_frm.cscript, new erpnext.support.SupportTicket({frm: cur_frm})); $.extend(cur_frm.cscript, { onload: function(doc, dt, dn) { From 517b30a11de6ef661ad62aa3332d0fb76e563d57 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Tue, 24 Sep 2013 12:29:35 +0530 Subject: [PATCH 017/123] fix for new wnf path stuff --- patches/april_2013/p05_update_file_data.py | 2 +- patches/april_2013/p06_update_file_size.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index e03abc6b65..664f9a4a0d 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -52,7 +52,7 @@ def update_for_doc(doctype, doc): exists = True if not (filename.startswith("http://") or filename.startswith("https://")): - if not os.path.exists(webnotes.utils.get_path("public", "files", filename)): + if not os.path.exists(webnotes.utils.get_storage_path(webnotes.conf.files_path, filename)): exists = False if exists: diff --git a/patches/april_2013/p06_update_file_size.py b/patches/april_2013/p06_update_file_size.py index 6879625ad9..be8c400915 100644 --- a/patches/april_2013/p06_update_file_size.py +++ b/patches/april_2013/p06_update_file_size.py @@ -4,7 +4,7 @@ import webnotes, os, webnotes.utils def execute(): - files_path = webnotes.utils.get_path("public", "files") + files_path = webnotes.utils.get_storage_path(webnotes.conf.files_path) webnotes.conn.auto_commit_on_many_writes = 1 for f in webnotes.conn.sql("""select name, file_name from @@ -14,4 +14,4 @@ def execute(): if os.path.exists(filepath): webnotes.conn.set_value("File Data", f.name, "file_size", os.stat(filepath).st_size) - webnotes.conn.auto_commit_on_many_writes = 0 \ No newline at end of file + webnotes.conn.auto_commit_on_many_writes = 0 From de8b6aadafbde05ac5a56d199c083e599068aead Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 24 Sep 2013 17:17:39 +0530 Subject: [PATCH 018/123] [minor] fixes for import conf --- portal/templates/pages/profile.py | 2 +- selling/utils/cart.py | 6 +++--- setup/doctype/backup_manager/backup_googledrive.py | 2 +- setup/doctype/email_digest/email_digest.py | 2 +- startup/boot.py | 2 +- startup/event_handlers.py | 4 ++-- support/doctype/newsletter/newsletter.py | 2 +- utilities/demo/demo_control_panel.py | 2 +- utilities/demo/make_demo.py | 6 +++++- utilities/demo/make_erpnext_demo.py | 4 ++-- 10 files changed, 18 insertions(+), 14 deletions(-) diff --git a/portal/templates/pages/profile.py b/portal/templates/pages/profile.py index 8edd830d47..3d6a86f9cc 100644 --- a/portal/templates/pages/profile.py +++ b/portal/templates/pages/profile.py @@ -33,7 +33,7 @@ def update_profile(fullname, password=None, company_name=None, mobile_no=None, p return _("Name is required") webnotes.conn.set_value("Profile", webnotes.session.user, "first_name", fullname) - webnotes.add_cookies["full_name"] = fullname + webnotes._response.set_cookie("full_name", fullname) return _("Updated") \ No newline at end of file diff --git a/selling/utils/cart.py b/selling/utils/cart.py index fc7d062d0d..92d37ea969 100644 --- a/selling/utils/cart.py +++ b/selling/utils/cart.py @@ -12,8 +12,8 @@ class WebsitePriceListMissingError(webnotes.ValidationError): pass def set_cart_count(quotation=None): if not quotation: quotation = _get_cart_quotation() - webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get( - {"parentfield": "quotation_details"})) or "") + cart_count = cstr(len(quotation.doclist.get({"parentfield": "quotation_details"}))) + webnotes._response.set_cookie("cart_count", cart_count) @webnotes.whitelist() def get_cart_quotation(doclist=None): @@ -47,7 +47,7 @@ def place_order(): sales_order.ignore_permissions = True sales_order.insert() sales_order.submit() - webnotes.add_cookies["cart_count"] = "" + webnotes._response.set_cookie("cart_count", "") return sales_order.doc.name diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index ee795186da..daf852c425 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -115,7 +115,7 @@ def get_gdrive_flow(): from oauth2client.client import OAuth2WebServerFlow from webnotes import conf - if not hasattr(conf, "gdrive_client_id"): + if not "gdrive_client_id" in conf: webnotes.msgprint(_("Please set Google Drive access keys in") + " conf.py", raise_exception=True) diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py index 2a9acaa8b9..a05bae9896 100644 --- a/setup/doctype/email_digest/email_digest.py +++ b/setup/doctype/email_digest/email_digest.py @@ -458,7 +458,7 @@ def send(): now_date = now_datetime().date() from webnotes import conf - if hasattr(conf, "expires_on") and now_date > getdate(conf.expires_on): + if "expires_on" in conf and now_date > getdate(conf.expires_on): # do not send email digests to expired accounts return diff --git a/startup/boot.py b/startup/boot.py index 20887f720c..d27c0b73e3 100644 --- a/startup/boot.py +++ b/startup/boot.py @@ -34,7 +34,7 @@ def boot_session(bootinfo): # load subscription info from webnotes import conf for key in ['max_users', 'expires_on', 'max_space', 'status', 'commercial_support']: - if hasattr(conf, key): bootinfo[key] = getattr(conf, key) + if key in conf: bootinfo[key] = conf.get(key) bootinfo['docs'] += webnotes.conn.sql("""select name, default_currency, cost_center from `tabCompany`""", as_dict=1, update={"doctype":":Company"}) diff --git a/startup/event_handlers.py b/startup/event_handlers.py index a333857b1b..fc95414baf 100644 --- a/startup/event_handlers.py +++ b/startup/event_handlers.py @@ -35,13 +35,13 @@ def on_login_post_session(login_manager): set_cart_count() def on_logout(login_manager): - webnotes.add_cookies["cart_count"] = "" + webnotes._response.set_cookie("cart_count", "") def check_if_expired(): """check if account is expired. If expired, do not allow login""" from webnotes import conf # check if expires_on is specified - if not hasattr(conf, 'expires_on'): return + if not 'expires_on' in conf: return # check if expired from datetime import datetime, date diff --git a/support/doctype/newsletter/newsletter.py b/support/doctype/newsletter/newsletter.py index 13ad47a0d8..a6b5aa29e8 100644 --- a/support/doctype/newsletter/newsletter.py +++ b/support/doctype/newsletter/newsletter.py @@ -91,7 +91,7 @@ class DocType(): raise_exception=1) from webnotes import conf - if getattr(conf, "status", None) == "Trial": + if (conf.get("status") or None) == "Trial": webnotes.msgprint(_("""Sending newsletters is not allowed for Trial users, \ to prevent abuse of this feature."""), raise_exception=1) diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py index 1da690245c..3123f41e08 100644 --- a/utilities/demo/demo_control_panel.py +++ b/utilities/demo/demo_control_panel.py @@ -2,7 +2,7 @@ def on_login(self): from webnotes.utils import validate_email_add from webnotes import conf - if hasattr(conf, "demo_notify_url"): + if "demo_notify_url" in conf: if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email): import requests response = requests.post(conf.demo_notify_url, data={ diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 883186791a..99bc018394 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -36,11 +36,15 @@ def make(reset=False, simulate=True): if reset: setup() + else: + webnotes.connect() + if simulate: _simulate() - + def setup(): install() + webnotes.connect() complete_setup() make_customers_suppliers_contacts() make_items() diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 6426367a95..4a72e4b589 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -5,9 +5,9 @@ if __name__=="__main__": import webnotes, os import utilities.demo.make_demo -def make_demo_app(): +def make_demo_app(site=None): webnotes.mute_emails = 1 - webnotes.connect() + webnotes.connect(site) utilities.demo.make_demo.make(reset=True, simulate=False) # setup demo user etc so that the site it up faster, while the data loads make_demo_user() From 10dce341c823d107d81246a87c07a82bcf1ca90b Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Wed, 25 Sep 2013 11:09:33 +0530 Subject: [PATCH 019/123] [pos] pos view fixed for all purchase & sales cycle --- .../purchase_invoice/purchase_invoice.py | 25 ++++----- accounts/doctype/sales_invoice/pos.js | 52 ++++++++++++++----- accounts/doctype/sales_invoice/pos.py | 6 ++- .../purchase_common/purchase_common.js | 3 +- public/js/transaction.js | 23 ++++++++ selling/doctype/sales_common/sales_common.js | 3 +- selling/utils/__init__.py | 1 + utilities/transaction_base.py | 1 + 8 files changed, 83 insertions(+), 31 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 0538323561..ad7ebd90de 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -62,19 +62,20 @@ class DocType(BuyingController): "purchase_receipt_details") def get_credit_to(self): - acc_head = sql("""select name, credit_days from `tabAccount` - where (name = %s or (master_name = %s and master_type = 'supplier')) - and docstatus != 2 and company = %s""", - (cstr(self.doc.supplier) + " - " + self.company_abbr, - self.doc.supplier, self.doc.company)) - ret = {} - if acc_head and acc_head[0][0]: - ret['credit_to'] = acc_head[0][0] - if not self.doc.due_date: - ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0) - elif not acc_head: - msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company)) + if self.doc.supplier: + acc_head = sql("""select name, credit_days from `tabAccount` + where (name = %s or (master_name = %s and master_type = 'supplier')) + and docstatus != 2 and company = %s""", + (cstr(self.doc.supplier) + " - " + self.company_abbr, + self.doc.supplier, self.doc.company)) + + if acc_head and acc_head[0][0]: + ret['credit_to'] = acc_head[0][0] + if not self.doc.due_date: + ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0) + elif not acc_head: + msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company)) return ret def set_supplier_defaults(self): diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 4ef239744b..ca5618b345 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -132,7 +132,7 @@ erpnext.POS = Class.extend({ "options": "Item Group", "label": "Item Group", "fieldname": "pos_item_group", - "placeholder": "Filter by Item Group" + "placeholder": "Item Group" }, parent: this.wrapper.find(".item-group-area") }); @@ -150,7 +150,7 @@ erpnext.POS = Class.extend({ "options": "Item", "label": "Item", "fieldname": "pos_item", - "placeholder": "Select Item" + "placeholder": "Item" }, parent: this.wrapper.find(".search-area") }); @@ -167,7 +167,7 @@ erpnext.POS = Class.extend({ "fieldtype": "Data", "label": "Barcode", "fieldname": "pos_barcode", - "placeholder": "Select Barcode" + "placeholder": "Barcode" }, parent: this.wrapper.find(".barcode-area") }); @@ -215,7 +215,9 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (cur_frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc[me.party.toLowerCase()]) { + if(!cur_frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && + cur_frm.doc.quotation_to == "Customer") + || me.frm.doctype != "Quotation")) { msgprint("Please select " + me.party + " first."); return; } @@ -282,6 +284,16 @@ erpnext.POS = Class.extend({ $.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name, this.frm.cscript.fname, this.frm.doctype), function(i, d) { + + if (me.sales_or_purchase == "Sales") { + item_amount = d.export_amount; + rate = d.export_rate; + } + else { + item_amount = d.import_amount; + rate = d.import_rate; + } + $(repl('\ %(item_code)s%(item_name)s\ " + d.item_name), qty: d.qty, - rate: format_currency(d.ref_rate, cur_frm.doc.currency), - amount: format_currency(d.export_amount, cur_frm.doc.currency) + rate: format_currency(rate, cur_frm.doc.currency), + amount: format_currency(item_amount, cur_frm.doc.currency) } )).appendTo($items); }); @@ -312,15 +324,24 @@ erpnext.POS = Class.extend({ ', { description: d.description, rate: d.rate, - tax_amount: format_currency(d.tax_amount, me.frm.doc.currency) + tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate), + me.frm.doc.currency) })).appendTo(".tax-table tbody"); }); // set totals - this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, - cur_frm.doc.currency)); - this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.currency)); + if (this.sales_or_purchase == "Sales") { + this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, + cur_frm.doc.currency)); + this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, + cur_frm.doc.currency)); + } + else { + this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import, + cur_frm.doc.currency)); + this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import, + cur_frm.doc.currency)); + } // if form is local then only run all these functions if (cur_frm.doc.docstatus===0) { @@ -366,9 +387,12 @@ erpnext.POS = Class.extend({ if (this.frm.doctype != "Sales Invoice") $(".make-payment").hide(); - if (this.frm.doctype == "Quotation") - if (cur_frm.doc.quotation_to=="Customer") - this.party_field.remove(); + // If quotation to is not Customer then remove party + if (this.frm.doctype == "Quotation") { + this.party_field.$wrapper.remove(); + if (cur_frm.doc.quotation_to == "Customer") + this.make_party(); + } }, refresh_delete_btn: function() { $(".delete-items").toggle($(".item-cart .warning").length ? true : false); diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py index d919c1b548..44fe40d8de 100644 --- a/accounts/doctype/sales_invoice/pos.py +++ b/accounts/doctype/sales_invoice/pos.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import webnotes -from webnotes import msgprint, errprint @webnotes.whitelist() def get_items(price_list, sales_or_purchase, item=None, item_group=None): @@ -36,6 +35,11 @@ def get_item_from_barcode(barcode): return webnotes.conn.sql("""select name from `tabItem` where barcode=%s""", (barcode), as_dict=1) +@webnotes.whitelist() +def get_item_from_serial_no(serial_no): + return webnotes.conn.sql("""select name, item_code from `tabSerial No` where + name=%s""", (serial_no), as_dict=1) + @webnotes.whitelist() def get_mode_of_payment(): return webnotes.conn.sql("""select name from `tabMode of Payment`""", as_dict=1) \ No newline at end of file diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 2dfe65515a..433a76fba7 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -108,8 +108,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ var item = wn.model.get_doc(cdt, cdn); if(item.item_code) { if(!this.validate_company_and_party("supplier")) { - item.item_code = null; - refresh_field("item_code", item.name, item.parentfield); + cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove(); } else { return this.frm.call({ method: "buying.utils.get_item_details", diff --git a/public/js/transaction.js b/public/js/transaction.js index 1a1c98ca6b..e12d1084e9 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -232,6 +232,29 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ tax_rate: function(doc, cdt, cdn) { this.calculate_taxes_and_totals(); }, + + // serial_no: function(doc, cdt, cdn) { + // var me = this; + // var item = wn.model.get_doc(cdt, cdn); + // if (!item.item_code) { + // wn.call({ + // method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no', + // args: {serial_no: this.serial_no.$input.val()}, + // callback: function(r) { + // if (r.message) { + // var item_code = r.message[0].item_code; + // var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", + // this.frm.cscript.fname); + // child.item_code = item_code; + // me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); + // } + // else + // msgprint(wn._("Invalid Serial No.")); + // me.refresh(); + // } + // }); + // } + // }, row_id: function(doc, cdt, cdn) { var tax = wn.model.get_doc(cdt, cdn); diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js index dc58377e4b..c87e823dba 100644 --- a/selling/doctype/sales_common/sales_common.js +++ b/selling/doctype/sales_common/sales_common.js @@ -162,8 +162,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ var item = wn.model.get_doc(cdt, cdn); if(item.item_code || item.barcode) { if(!this.validate_company_and_party("customer")) { - item.item_code = null; - refresh_field("item_code", item.name, item.parentfield); + cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove(); } else { return this.frm.call({ method: "selling.utils.get_item_details", diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 224944dd88..801d82bf40 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -34,6 +34,7 @@ def get_item_details(args): "plc_conversion_rate": 1.0 } """ + if isinstance(args, basestring): args = json.loads(args) args = webnotes._dict(args) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 2535db7ab5..57591fd321 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -425,6 +425,7 @@ def get_address_territory(address_doc): def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company): """common validation for currency and price list currency""" + if conversion_rate == 0: msgprint(conversion_rate_label + _(' cannot be 0'), raise_exception=True) From a80f2e44315319fc3c3cbcaa7d14434ddf755da1 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Wed, 25 Sep 2013 12:40:33 +0530 Subject: [PATCH 020/123] refactor site_path --- patches/april_2013/p05_update_file_data.py | 2 +- patches/april_2013/p06_update_file_size.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py index 664f9a4a0d..47d6de9186 100644 --- a/patches/april_2013/p05_update_file_data.py +++ b/patches/april_2013/p05_update_file_data.py @@ -52,7 +52,7 @@ def update_for_doc(doctype, doc): exists = True if not (filename.startswith("http://") or filename.startswith("https://")): - if not os.path.exists(webnotes.utils.get_storage_path(webnotes.conf.files_path, filename)): + if not os.path.exists(webnotes.utils.get_site_path(webnotes.conf.files_path, filename)): exists = False if exists: diff --git a/patches/april_2013/p06_update_file_size.py b/patches/april_2013/p06_update_file_size.py index be8c400915..973cea94d7 100644 --- a/patches/april_2013/p06_update_file_size.py +++ b/patches/april_2013/p06_update_file_size.py @@ -4,7 +4,7 @@ import webnotes, os, webnotes.utils def execute(): - files_path = webnotes.utils.get_storage_path(webnotes.conf.files_path) + files_path = webnotes.utils.get_site_path(webnotes.conf.files_path) webnotes.conn.auto_commit_on_many_writes = 1 for f in webnotes.conn.sql("""select name, file_name from From f879a9dc2e8ceff2017ff5c0dd10d8e468dd232a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 26 Sep 2013 15:56:54 +0530 Subject: [PATCH 021/123] [minor] wnf refactor, fixes in demo --- stock/doctype/warehouse/warehouse.py | 2 +- utilities/demo/make_demo.py | 16 +++++++++++----- utilities/demo/make_erpnext_demo.py | 8 ++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index 1494428549..faf9b04e00 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -31,7 +31,7 @@ class DocType: if not webnotes.conn.get_value("Account", {"account_type": "Warehouse", "master_name": self.doc.name}) and not webnotes.conn.get_value("Account", {"account_name": self.doc.warehouse_name}): - if self.doc.__islocal or not webnotes.conn.get_value("Stock Ledger Entry", + if self.doc.fields.get("__islocal") or not webnotes.conn.get_value("Stock Ledger Entry", {"warehouse": self.doc.name}): self.validate_parent_account() ac_bean = webnotes.bean({ diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 2d2d07e0ea..6c6ccab4df 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -34,17 +34,20 @@ def make(reset=False, simulate=True): webnotes.mute_emails = True webnotes.rollback_on_exception = True + if not webnotes.conf.demo_db_name: + raise Exception("conf.py does not have demo_db_name") + if reset: setup() else: - webnotes.connect() + webnotes.connect(db_name=webnotes.conf.demo_db_name) if simulate: _simulate() def setup(): install() - webnotes.connect() + webnotes.connect(db_name=webnotes.conf.demo_db_name) complete_setup() make_customers_suppliers_contacts() make_items() @@ -142,14 +145,17 @@ def run_stock(current_date): # make purchase requests if can_make("Purchase Receipt"): from buying.doctype.purchase_order.purchase_order import make_purchase_receipt + from stock.stock_ledger import NegativeStockError report = "Purchase Order Items To Be Received" for po in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Purchase Receipt")]: pr = webnotes.bean(make_purchase_receipt(po)) pr.doc.posting_date = current_date pr.doc.fiscal_year = "2013" pr.insert() - pr.submit() - webnotes.conn.commit() + try: + pr.submit() + webnotes.conn.commit() + except NegativeStockError: pass # make delivery notes (if possible) if can_make("Delivery Note"): @@ -363,7 +369,7 @@ def install(): from webnotes.install_lib.install import Installer from webnotes import conf inst = Installer('root') - inst.import_from_db(conf.demo_db_name, verbose = 1) + inst.install(conf.demo_db_name, verbose=1, force=1) def complete_setup(): print "Complete Setup..." diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 4a72e4b589..50c66a3233 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -7,7 +7,9 @@ import utilities.demo.make_demo def make_demo_app(site=None): webnotes.mute_emails = 1 - webnotes.connect(site) + webnotes.init(site=site) + webnotes.connect(db_name=webnotes.conf.demo_db_name, site=site) + utilities.demo.make_demo.make(reset=True, simulate=False) # setup demo user etc so that the site it up faster, while the data loads make_demo_user() @@ -116,4 +118,6 @@ def make_demo_on_login_script(): webnotes.conn.commit() if __name__=="__main__": - make_demo_app() + import sys + site = sys.argv[1:] + make_demo_app(site=site and site[0] or None) From c875300fe2c3aa6e52752b83d324d47d793b2198 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 26 Sep 2013 17:54:51 +0530 Subject: [PATCH 022/123] [minor] moved wn-web.js and wn-web.css to memcache --- startup/event_handlers.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/startup/event_handlers.py b/startup/event_handlers.py index fc95414baf..a0126118bb 100644 --- a/startup/event_handlers.py +++ b/startup/event_handlers.py @@ -65,9 +65,6 @@ def check_if_expired(): raise webnotes.AuthenticationError def on_build(): - from website.doctype.website_settings.make_web_include_files import make - make() - from home.page.latest_updates import latest_updates latest_updates.make() From 6111b1edb610f89dc24f8d48ec305d141a7c30b7 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 26 Sep 2013 17:49:53 -0300 Subject: [PATCH 023/123] Fix Translation in Sales Order.js I'll be fixing some points that I miss translation. --- selling/doctype/sales_order/sales_order.js | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index 33699f05d8..402099259f 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -26,34 +26,34 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( cur_frm.dashboard.add_progress(cint(doc.per_billed) + wn._("% Billed"), doc.per_billed); - cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); + cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms); // delivery note if(flt(doc.per_delivered, 2) < 100 && doc.order_type=='Sales') - cur_frm.add_custom_button('Make Delivery', this.make_delivery_note); + cur_frm.add_custom_button(wn._('Make Delivery'), this.make_delivery_note); // maintenance if(flt(doc.per_delivered, 2) < 100 && (doc.order_type !='Sales')) { - cur_frm.add_custom_button('Make Maint. Visit', this.make_maintenance_visit); - cur_frm.add_custom_button('Make Maint. Schedule', + cur_frm.add_custom_button(wn._('Make Maint. Visit'), this.make_maintenance_visit); + cur_frm.add_custom_button(wn._('Make Maint. Schedule'), this.make_maintenance_schedule); } // indent if(!doc.order_type || (doc.order_type == 'Sales')) - cur_frm.add_custom_button('Make ' + wn._('Material Request'), + cur_frm.add_custom_button(wn._('Make ') + wn._('Material Request'), this.make_material_request); // sales invoice if(flt(doc.per_billed, 2) < 100) - cur_frm.add_custom_button('Make Invoice', this.make_sales_invoice); + cur_frm.add_custom_button(wn._('Make Invoice'), this.make_sales_invoice); // stop if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100) - cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Sales Order']); + cur_frm.add_custom_button(wn._('Stop!'), cur_frm.cscript['Stop Sales Order']); } else { // un-stop - cur_frm.dashboard.set_headline_alert("Stopped", "alert-danger", "icon-stop"); - cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Sales Order']); + cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop"); + cur_frm.add_custom_button(wn._('Unstop'), cur_frm.cscript['Unstop Sales Order']); } } @@ -157,7 +157,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) { cur_frm.cscript['Stop Sales Order'] = function() { var doc = cur_frm.doc; - var check = confirm("Are you sure you want to STOP " + doc.name); + var check = confirm(wn._("Are you sure you want to STOP ") + doc.name); if (check) { return $c('runserverobj', { @@ -172,7 +172,7 @@ cur_frm.cscript['Stop Sales Order'] = function() { cur_frm.cscript['Unstop Sales Order'] = function() { var doc = cur_frm.doc; - var check = confirm("Are you sure you want to UNSTOP " + doc.name); + var check = confirm(wn._("Are you sure you want to UNSTOP ") + doc.name); if (check) { return $c('runserverobj', { @@ -188,4 +188,4 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) { if(cint(wn.boot.notification_settings.sales_order)) { cur_frm.email_doc(wn.boot.notification_settings.sales_order_message); } -}; \ No newline at end of file +}; From 18762925bcbd9591c275610cc4ec34dc184a51f3 Mon Sep 17 00:00:00 2001 From: Maxwell Date: Thu, 26 Sep 2013 17:54:46 -0300 Subject: [PATCH 024/123] Fix translation in Customer.js I'll be fixing some points that I miss translation. --- selling/doctype/customer/customer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js index 4e2f42c734..d2c632530b 100644 --- a/selling/doctype/customer/customer.js +++ b/selling/doctype/customer/customer.js @@ -45,7 +45,7 @@ cur_frm.cscript.setup_dashboard = function(doc) { cur_frm.dashboard.reset(doc); if(doc.__islocal) return; - cur_frm.dashboard.set_headline('Loading...') + cur_frm.dashboard.set_headline(''+ wn._('Loading...')+ '') cur_frm.dashboard.add_doctype_badge("Opportunity", "customer"); cur_frm.dashboard.add_doctype_badge("Quotation", "customer"); @@ -99,7 +99,7 @@ cur_frm.cscript.make_contact = function() { return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc" }, as_dict: 1, - no_results_message: 'No contacts created', + no_results_message: wn._('No contacts created'), render_row: cur_frm.cscript.render_contact_row, }); // note: render_contact_row is defined in contact_control.js @@ -119,4 +119,4 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) { return{ query:"controllers.queries.lead_query" } -} \ No newline at end of file +} From 2428e8d1b7ce13c5b60bb38bd590e6466d678c31 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 27 Sep 2013 12:32:26 +0530 Subject: [PATCH 025/123] [pos] [minor] fix for cur_frm --- accounts/doctype/sales_invoice/pos.js | 40 +++++++++++++------------- selling/doctype/quotation/quotation.js | 6 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index ca5618b345..e19652d25f 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -213,10 +213,10 @@ erpnext.POS = Class.extend({ }); // if form is local then allow this function - if (cur_frm.doc.docstatus===0) { + if (me.frm.doc.docstatus===0) { $("div.pos-item").on("click", function() { - if(!cur_frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && - cur_frm.doc.quotation_to == "Customer") + if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && + me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { msgprint("Please select " + me.party + " first."); return; @@ -304,8 +304,8 @@ erpnext.POS = Class.extend({ item_code: d.item_code, item_name: d.item_name===d.item_code ? "" : ("
" + d.item_name), qty: d.qty, - rate: format_currency(rate, cur_frm.doc.currency), - amount: format_currency(item_amount, cur_frm.doc.currency) + rate: format_currency(rate, me.frm.doc.currency), + amount: format_currency(item_amount, me.frm.doc.currency) } )).appendTo($items); }); @@ -332,19 +332,19 @@ erpnext.POS = Class.extend({ // set totals if (this.sales_or_purchase == "Sales") { this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export, - cur_frm.doc.currency)); + me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export, - cur_frm.doc.currency)); + me.frm.doc.currency)); } else { this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import, - cur_frm.doc.currency)); + me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import, - cur_frm.doc.currency)); + me.frm.doc.currency)); } // if form is local then only run all these functions - if (cur_frm.doc.docstatus===0) { + if (this.frm.doc.docstatus===0) { $("input.qty").on("focus", function() { $(this).select(); }); @@ -371,11 +371,11 @@ erpnext.POS = Class.extend({ }); me.refresh_delete_btn(); - cur_frm.pos.barcode.$input.focus(); + this.frm.pos.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons - if (cur_frm.doc.docstatus>=1) { + if (this.frm.doc.docstatus>=1) { me.wrapper.find('input, button').each(function () { $(this).prop('disabled', true); }); @@ -390,7 +390,7 @@ erpnext.POS = Class.extend({ // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { this.party_field.$wrapper.remove(); - if (cur_frm.doc.quotation_to == "Customer") + if (this.frm.doc.quotation_to == "Customer") this.make_party(); } }, @@ -435,8 +435,8 @@ erpnext.POS = Class.extend({ } } }); - cur_frm.fields_dict[this.frm.cscript.fname].grid.refresh(); - cur_frm.script_manager.trigger("calculate_taxes_and_totals"); + this.frm.fields_dict[this.frm.cscript.fname].grid.refresh(); + this.frm.script_manager.trigger("calculate_taxes_and_totals"); me.frm.dirty(); me.refresh(); }, @@ -470,15 +470,15 @@ erpnext.POS = Class.extend({ "total_amount": $(".grand-total").text() }); dialog.show(); - cur_frm.pos.barcode.$input.focus(); + me.frm.pos.barcode.$input.focus(); dialog.get_input("total_amount").prop("disabled", true); dialog.fields_dict.pay.input.onclick = function() { - cur_frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment); - cur_frm.set_value("paid_amount", dialog.get_values().total_amount); - cur_frm.cscript.mode_of_payment(cur_frm.doc); - cur_frm.save(); + me.frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment); + me.frm.set_value("paid_amount", dialog.get_values().total_amount); + me.frm.cscript.mode_of_payment(me.frm.doc); + me.frm.save(); dialog.hide(); me.refresh(); }; diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js index 33ba0933bb..e20308f18e 100644 --- a/selling/doctype/quotation/quotation.js +++ b/selling/doctype/quotation/quotation.js @@ -83,12 +83,12 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({ }, validate_company_and_party: function(party_field) { - if(this.frm.doc.quotation_to == "Lead") { - return true; - } else if(!this.frm.doc.quotation_to) { + if(!this.frm.doc.quotation_to) { msgprint(wn._("Please select a value for" + " " + wn.meta.get_label(this.frm.doc.doctype, "quotation_to", this.frm.doc.name))); return false; + } else if (this.frm.doc.quotation_to == "Lead") { + return true; } else { return this._super(party_field); } From 8db093b4c6dedc6f326c7bb786221a50006383e7 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 27 Sep 2013 14:08:55 +0530 Subject: [PATCH 026/123] [minor] update password --- utilities/demo/make_demo.py | 1 + utilities/demo/make_erpnext_demo.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 6c6ccab4df..4f30df62be 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -40,6 +40,7 @@ def make(reset=False, simulate=True): if reset: setup() else: + webnotes.conn.close() webnotes.connect(db_name=webnotes.conf.demo_db_name) if simulate: diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 50c66a3233..a57441b556 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -8,7 +8,6 @@ import utilities.demo.make_demo def make_demo_app(site=None): webnotes.mute_emails = 1 webnotes.init(site=site) - webnotes.connect(db_name=webnotes.conf.demo_db_name, site=site) utilities.demo.make_demo.make(reset=True, simulate=False) # setup demo user etc so that the site it up faster, while the data loads @@ -18,6 +17,8 @@ def make_demo_app(site=None): utilities.demo.make_demo.make(reset=False, simulate=True) def make_demo_user(): + from webnotes.auth import _update_password + roles = ["Accounts Manager", "Analytics", "Expense Approver", "Accounts User", "Leave Approver", "Blogger", "Customer", "Sales Manager", "Employee", "Support Manager", "HR Manager", "HR User", "Maintenance Manager", "Maintenance User", "Material Manager", @@ -44,10 +45,10 @@ def make_demo_user(): p.doc.last_name = "User" p.doc.enabled = 1 p.doc.user_type = "ERPNext Demo" - p.doc.new_password = "demo" p.insert() add_roles(p) p.save() + _update_password("demo@erpnext.com", "demo") # make system manager user if webnotes.conn.exists("Profile", "admin@erpnext.com"): @@ -59,11 +60,11 @@ def make_demo_user(): p.doc.last_name = "User" p.doc.enabled = 1 p.doc.user_type = "System User" - p.doc.new_password = "admin010123" p.insert() roles.append("System Manager") add_roles(p) p.save() + _update_password("admin@erpnext.com", "admin010123") # only read for newsletter webnotes.conn.sql("""update `tabDocPerm` set `write`=0, `create`=0, `cancel`=0 From a3d12bde9d1977c60b5671c006f40102c1887824 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 27 Sep 2013 16:33:22 +0530 Subject: [PATCH 027/123] [fix] [minor] gross profit report --- accounts/report/gross_profit/gross_profit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index d9c20d5ccc..9917b69697 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -55,7 +55,7 @@ def get_stock_ledger_entries(filters): from `tabStock Ledger Entry`""" if filters.get("company"): - query += """ and company=%(company)s""" + query += """ where company=%(company)s""" query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc" From 2ba61236c1caae841faa477b71431cec485c4d1e Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 27 Sep 2013 21:08:37 +0530 Subject: [PATCH 028/123] [price list] make new grid --- setup/doctype/price_list/price_list.js | 301 +++++++++++++++++++++++++ 1 file changed, 301 insertions(+) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index f3adc72757..6dfbd0f1ee 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -5,4 +5,305 @@ $.extend(cur_frm.cscript, { onload: function() { erpnext.add_for_territory(); }, +}); + +cur_frm.cscript.refresh = function(doc, cdt, cdn) { + cur_frm.cscript.show_item_prices(); +} + +cur_frm.cscript.show_item_prices = function() { + var counter = 0; + var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); + + new wn.ui.form.TableGrid({ + parent: cur_frm.fields_dict.item_prices.wrapper, + frm: cur_frm, + table_field: wn.model.get("DocField", {parent:"Price List", fieldname:"item_prices"})[0] + }); +} + +wn.ui.form.TableGrid = Class.extend({ + init: function(opts) { + $.extend(this, opts); + this.fields = wn.model.get("DocField", {parent: this.table_field.options}); + this.make_table(); + }, + make_table: function() { + var me = this; + // Creating table & assigning attributes + var grid_table = document.createElement("table"); + $(grid_table).attr("class", "table table-hover table-bordered grid"); + + // Appending header & rows to table + + $(this.make_table_headers()).appendTo(grid_table); + $(this.make_table_rows()).appendTo(grid_table); + + // Creating button to add new row + var btn_div = document.createElement("div"); + var new_row_btn = document.createElement("button"); + $new_row_btn = $(new_row_btn); + $new_row_btn.attr({ + "class": "btn btn-success table-new-row", + "title": "Add new row" + }); + var btn_icon = document.createElement("i"); + $(btn_icon).attr("class", "icon-plus"); + $(btn_icon).appendTo(new_row_btn); + $new_row_btn.append(" Add new row"); + $new_row_btn.appendTo(btn_div); + + // Appending table & button to parent + var $grid_table = $(grid_table).appendTo($(this.parent)); + var $btn_div = $(btn_div).appendTo($(this.parent)); + + $btn_div.on("click", ".table-new-row", function() { + me.make_dialog(); + return false; + }); + + $grid_table.on("click", ".table-row", function() { + me.make_dialog(this); + return false; + }); + }, + make_table_headers: function() { + var me = this; + var header = document.createElement("thead"); + + // Creating header row + var row = document.createElement("tr"); + $(row).attr({ + "class": "active", + "style": "height:50px" + }); + $(row).appendTo(header); + + // Creating head first cell + var th = document.createElement("th"); + $(th).attr({ + "width": "8%", + "style": "vertical-align:middle", + "class": "text-center" + }); + $(th).html("#"); + $(th).appendTo(row); + + // Make other headers with label as heading + $.each(this.fields, function(i, obj) { + if (obj.in_list_view===1) + var th = document.createElement("th"); + $(th).attr("style", "vertical-align:middle"); + $(th).html(obj.label); + $(th).appendTo(row); + }); + + return header; + }, + make_table_rows: function() { + var me = this; + + // Creating table body + var table_body = document.createElement("tbody"); + $(table_body).attr("style", "cursor:pointer"); + + $.each(wn.model.get_children(this.table_field.options, this.frm.doc.name, + this.table_field.fieldname, this.frm.doctype), function(index, d) { + + // Creating table row + var tr = document.createElement("tr"); + $(tr).attr({ + "class": "table-row", + "data-idx": d.idx + }); + + // Creating table data & appending to row + var td = document.createElement("td"); + $(td).attr("class", "text-center"); + $(td).html(d.idx); + $(td).appendTo(tr); + + $.each(me.fields, function(i, obj) { + if (obj.in_list_view===1) { + var td = document.createElement("td"); + $(td).attr({ + "data-fieldtype": obj.fieldtype, + "data-fieldname": obj.fieldname, + "data-fieldvalue": d[obj.fieldname], + "data-doc_name": d["name"] + }); + $(td).html(d[obj.fieldname]); + + // if field is currency then add style & change text + if (obj.fieldtype=="Currency") { + $(td).attr("style", "text-align:right"); + $(td).html(format_currency(d[obj.fieldname], me.frm.doc.currency)); + } + + // Append td to row + $(td).appendTo(tr); + } + }); + + // Append row to table body + $(tr).appendTo(table_body); + }); + + return table_body; + }, + make_dialog: function(row) { + var me = this; + + this.dialog = new wn.ui.Dialog({ + title: this.table_field.options, + fields: this.fields + }); + + this.dialog.set_values(this.make_dialog_values(row)); + + $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); + this.dialog.show(); + + this.dialog.$wrapper.find('button.update').on('click', function() { + me.update_row(row); + }); + + this.dialog.$wrapper.find('button.delete').on('click', function() { + me.delete_row(row); + }); + return row; + }, + // make_dialog_fields: function() { + // var me = this; + // var fields = []; + + // $.each(this.fields, function(i, obj) { + // var dialog_field = { + // fieldtype: obj.fieldtype, + // fieldname: obj.fieldname, + // label: obj.label + // } + + // // check if fields has options + // if (obj.options) { + // var options = {options: obj.options} + // $.extend(dialog_field, options); + // } + + // // check if field is mandatory + // if (obj.reqd == 1) { + // var reqd = {reqd: obj.reqd} + // $.extend(dialog_field, reqd); + // } + + // fields.push(obj); + // }); + + // return fields; + // }, + make_dialog_values: function(row) { + var me = this; + var dialog_values = {}; + + $.each(this.fields, function(i, item) { + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + }); + + return dialog_values; + }, + make_dialog_buttons: function() { + var me = this; + var buttons = ''; + + // if user can delete then only add the delete button in dialog + if (wn.model.can_delete(me.frm.doc.doctype)) + buttons += ' '; + + return buttons; + }, + update_row: function(row) { + var me = this; + + if (!row) { + me.add_new_row(); + } + else { + $.each(me.fields, function(i, item) { + var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); + var val = me.dialog.get_values()[item.fieldname]; + + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), + item.fieldname, me.dialog.get_values()[item.fieldname]); + $td.attr('data-fieldvalue', val); + + // If field type is currency the update with format currency + if ($td.attr('data-fieldtype') == "Currency") + $td.html(format_currency(val, me.frm.doc.currency)); + else + $td.html(val); + }); + } + + this.dialog.hide(); + }, + delete_row: function(row) { + var me = this; + var doc_name = $(row).find('td:last').attr('data-doc_name'); + wn.model.clear_doc(me.table_field.options, doc_name); + $(row).remove(); + + // Re-assign idx + $.each($(this.parent).find(".grid tbody tr"), function(idx, data) { + $(data).attr("data-idx", idx + 1); + var $td = $(data).find('td:first'); + $td.html(idx + 1); + }); + this.dialog.hide(); + }, + add_new_row: function() { + var me = this; + var row = $(this.parent).find(".grid tbody tr"); + + // Creating new row + var new_row = document.createElement("tr"); + $(new_row).attr({ + "class": "table-row", + "data-idx": row.length + 1 + }); + + // Creating first table data + var td = document.createElement("td"); + $(td).attr("class", "text-center"); + $(td).html(row.length + 1); + $(td).appendTo(new_row); + + var child = wn.model.add_child(this.frm.doc, this.table_field.options, + this.table_field.fieldname); + + $.each(this.fields, function(i, obj) { + if (obj.in_list_view===1) { + child[obj.fieldname] = me.dialog.get_values()[obj.fieldname]; + + var td = document.createElement("td"); + $(td).attr({ + "data-fieldtype": obj.fieldtype, + "data-fieldname": obj.fieldname, + "data-fieldvalue": child[obj.fieldname], + "data-doc_name": child["name"] + }); + $(td).html(child[obj.fieldname]); + + // if field is currency then add style & change text + if (obj.fieldtype=="Currency") { + $(td).attr("style", "text-align:right"); + $(td).html(format_currency(child[obj.fieldname], me.frm.doc.currency)); + } + + // Append td to row + $(td).appendTo(new_row); + } + }); + + $(new_row).appendTo($(this.parent).find(".grid tbody")); + } }); \ No newline at end of file From d1972dd4caa8f56400442436decf5ca44deb544e Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 30 Sep 2013 10:44:13 +0530 Subject: [PATCH 029/123] [docs] new pages on doctype and markup --- docs/user/buying/docs.user.buying.supplier.md | 8 + .../buying/docs.user.buying.supplier_type.md | 6 +- docs/user/docs.user.md | 4 + .../docs.user.knowledge.accounting.md | 72 ++--- .../docs.user.knowledge.attachment_csv.md | 16 ++ .../knowledge/docs.user.knowledge.doctype.md | 267 ++++++++++++++++++ .../knowledge/docs.user.knowledge.markdown.md | 84 ++++++ docs/user/knowledge/docs.user.knowledge.md | 8 +- .../selling/docs.user.selling.customer.md | 4 +- .../user/setup/docs.user.setup.data_import.md | 6 +- docs/user/stock/docs.user.stock.item.md | 6 +- 11 files changed, 432 insertions(+), 49 deletions(-) create mode 100644 docs/user/knowledge/docs.user.knowledge.attachment_csv.md create mode 100644 docs/user/knowledge/docs.user.knowledge.doctype.md create mode 100644 docs/user/knowledge/docs.user.knowledge.markdown.md diff --git a/docs/user/buying/docs.user.buying.supplier.md b/docs/user/buying/docs.user.buying.supplier.md index e477fa2bed..3707fbe852 100644 --- a/docs/user/buying/docs.user.buying.supplier.md +++ b/docs/user/buying/docs.user.buying.supplier.md @@ -20,7 +20,15 @@ You can create a new Supplier via: > Tip: When you select a Supplier in any transaction, one Contact and Address gets pre-selected. This is the “Default Contact or Address”. So make sure you set your defaults correctly! +### Integration with Accounts +In ERPNext, there is a separate Account record for each Supplier, of Each company. + +When you create a new Supplier, ERPNext will automatically create an Account Ledger for the Supplier under “Accounts Receivable” in the Company set in the Supplier record. + +> Advanced Tip: If you want to change the Account Group under which the Supplier Account is created, you can set it in the Company master. + +If you want to create an Account in another Company, just change the Company value and “Save” the Supplier again. > Buying > Contact > New Contact diff --git a/docs/user/buying/docs.user.buying.supplier_type.md b/docs/user/buying/docs.user.buying.supplier_type.md index deaf01fcfc..3871991d63 100644 --- a/docs/user/buying/docs.user.buying.supplier_type.md +++ b/docs/user/buying/docs.user.buying.supplier_type.md @@ -3,9 +3,11 @@ "_label": "Supplier Type" } --- +A supplier may be distinguished from a contractor or subcontractor, who commonly adds specialized input to deliverables. A supplier is also known as a vendor. There are different types of suppliers based on their goods and products. -Based on what the suppliers supply, they are classified into different categories called Supplier Type. -There can be different types of suppliers. You can create your own category of Supplier Type. +ERPNext allows you to create your own categories of suppliers. These categories are known as Supplier Type. For Example, if your suppliers are mainly pharmaceutical companies and FMCG distributors, You can create a new Type for them and name them accordingly. + +Based on what the suppliers supply, they are classified into different categories called Supplier Type. There can be different types of suppliers. You can create your own category of Supplier Type. > Buying > Supplier Type > New Supplier Type diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index d9e7f2aac0..c45ca30a22 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -151,3 +151,7 @@ Contents 1. [Fiscal Year](docs.user.knowledge.fiscal_year.html) 1. [Accounting Knowledge](docs.user.knowledge.accounting.html) 1. [Accounting Entries](docs.user.knowledge.accounting_entries.html) + 1. [DocType Definitions](docs.user.knowledge.doctype.html) + 1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html) + 1. [Format using Markdown](docs.user.knowledge.markdown.html) + diff --git a/docs/user/knowledge/docs.user.knowledge.accounting.md b/docs/user/knowledge/docs.user.knowledge.accounting.md index 17304984cb..995d38cfe9 100644 --- a/docs/user/knowledge/docs.user.knowledge.accounting.md +++ b/docs/user/knowledge/docs.user.knowledge.accounting.md @@ -22,34 +22,34 @@ Accounting Entries The balance of account can be increased / decreased, depending on account type and transaction type. - +
- - - + + + - - - + + + - - - + + + - - - + + + - - - + + +
Account TypeTransaction TypeEffect on account balanceAccount TypeTransaction TypeEffect on account balance
DebitDebitIncreasesDebitDebitIncreases
DebitCreditDecreasesDebitCreditDecreases
CreditCreditIncreasesCreditCreditIncreases
CreditDebitDecreasesCreditDebitDecreases
@@ -62,48 +62,48 @@ This means that every accounting entry has two parts, one debit and one credit a As the company will receive a payment from customer, the customer is considered as an asset account. For booking income, company maintains an account called "Sales of Laptop". So, entries will be done in the following manner: - +
- - - + + + - - - + + + - - - + + +
AccountDebitCreditAccountDebitCredit
Customer A50000Customer A50000
Sales of Laptop50000Sales of Laptop50000
Customer A has made the payment, so customer balance should decreased based on the paid amount, which will increase "Cash" balance. - +
- - - + + + - - - + + + - - - + + +
AccountDebitCreditAccountDebitCredit
Customer A50000Customer A50000
Cash50000Cash50000
diff --git a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md new file mode 100644 index 0000000000..311934d7f4 --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md @@ -0,0 +1,16 @@ +--- +{ + "_label": "Attachement and CSV files" +} +--- + +#### How to Attach files? + +When you open a form, on the right sidebar, you will see a section to attach files. Click on “Add” and select the file you want to attach. Click on “Upload” and you are set. + +#### What is a CSV file? + +A CSV (Comma Separated Value) file is a data file that you can upload into ERPNext to update various data. Any spreadsheet file from popular spreadsheet applications like MS Excel or Open Office Spreadsheet can be saved as a CSV file. + +If you are using Microsoft Excel and using non-English characters, make sure to save your file encoded as UTF-8. For older versions of Excel, there is no clear way of saving as UTF-8. So save your file as a CSV, then open it in Notepad, and save as “UTF-8”. (Sorry blame Microsoft for this!) + diff --git a/docs/user/knowledge/docs.user.knowledge.doctype.md b/docs/user/knowledge/docs.user.knowledge.doctype.md new file mode 100644 index 0000000000..a2550d4f95 --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.doctype.md @@ -0,0 +1,267 @@ +--- +{ + "_label": "DocType" +} +--- + + + +ERPNext is a based on a “metadata” (data about data) framework that helps define all the different types of documents in the system. The basic building block of ERPNext is a DocType. + +A DocType represents both a table in the database and a form from which a user can enter data. + +Many DocTypes are single tables, but some work in groups. For example, Quotation has a “Quotation” DocType and a “Quotation Item” doctype for the Items table, among others. DocTypes contain a collection of fields called DocFields that form the basis of the columns in the database and the layout of the form. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ColumnDescription
NameName of the record
OwnerCreator and Owner of the record
Created onDate and Time of Creation
Modified On Date and Time of Modification
DocstatusStatus of the record
+ 0 = Saved/Draft
+ 1 = Submitted
+ 2 = Cancelled/Deleted +
ParentName of the Parent
Parent TypeType of Parent
Parent FieldSpecifying the relationship with the parent (there can be multiple child relationships with the same DocType).
Index(idx)Index (sequence) of the record in the child table.
+ +#### Single DocType + +There are a certain type of DocTypes that are “Single”, i.e. they have no table associated and have only one record of its fields. DocTypes such as Global Defaults, Production Planning Tool are “Single” DocTypes. + +#### Field Columns + +In the fields table, there are many columns, here is an explanation of the columns of the field table. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ColumnDescription
LabelField Label (that appears in the form).
TypeField Type
NameColumn name in the database, must be code friendly with no white spaces, special characters and capital letters.
optionsField settings:
+ For Select: List of options (each on a new line).
+ For Link: DocType that is “linked”.
+ For HTML: HTML Content +
Perm LevelPermission level (number) of the field. You can group fields by numbers, called levels, and apply rules on the levels.
WidthWidth of the field (in pixels) - useful for “Table” types.
ReqdChecked if field is mandatory (required).
In FilterChecked if field appears as a standard filter in old style reports.
HiddenChecked if field is hidden.
Print HideChecked if field is hidden in Print Formats.
Report HideChecked if field is hidden in old style reports.
Allow on SubmitChecked if this field can be edited after the document is “Submitted”.
Depends OnThe fieldname of the field that will decide whether this field will be shown or hidden. It is useful to hide un-necessary fields.
DescriptionDescription of the field
DefaultDefault value when a new record is created.
+ Note: “user” will set the current user as default and “today” will set today’s date (if the field is a Date field).
+ +#### Field Types and Options + +Here is a list of the different types of fields used to make / customize forms in ERPNext. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescriptionOptions/Setting
DataSingle line text field with 180 characters
SelectSelect from a pre-determined items in a drop-down.The “Options” contains the drop-down items, each on a new row
LinkLink an existing document / recordOptions contains the name of the type of document (DocType)
CurrencyNumber with 2 decimal places, that will be shown separated by commas for thousands etc. in Print.e.g. 1,000,000.00
FloatNumber with 6 decimal places.e.g. 3.141593
IntInteger (no decimals)e.g. 100
DateDateFormat can be selected in Global Defaults
TimeTime
Text
TextMulti-line text box without formatting features
Text editorMulti-line text box with formatting toolbar etc
CodeCode EditorOptions can include the type of language for syntax formatting. + Eg JS / Python / HTML
Table (Grid)
TableTable of child items linked to the record.Options contains the name of the DocType of the child table. For example “Sales Invoice Item” for “Sales Invoice”
Layout
Section BreakBreak into a new horizontal section.The layout in ERPNext is evaluated from top to bottom.
Column BreakBreak into a new vertical column.
HTMLAdd a static text / help / link etc in HTMLOptions contains the HTML.
Action
ButtonButton[for developers only]
+ + + + + + + \ No newline at end of file diff --git a/docs/user/knowledge/docs.user.knowledge.markdown.md b/docs/user/knowledge/docs.user.knowledge.markdown.md new file mode 100644 index 0000000000..b2f76be583 --- /dev/null +++ b/docs/user/knowledge/docs.user.knowledge.markdown.md @@ -0,0 +1,84 @@ +--- +{ + "_label": "Format Using Markdown" +} +--- + +Markdown is a simple way of writing text to format your content. Markdown allows you easy ways to format. + +1. Headings (h1 (largest), h2, h3, h4 and so on) +1. Paragraphs +1. Lists (numbered or bulleted) +1. Hyper links (links to other pages) +1. Images +1. Code +1. Embed HTML (HTML tags within your text) + +#### Headings + +Headings are specified by adding a `#` (hash) at the beginning of the line. The more the number of hashes, the smaller the heading: + + # This is a large heading. + + ### This is a smaller heading. + +#### Paragraphs + +To start a new paragraph, just make sure that there is an empty line at the beginning and end of the paragraph. + +To format text as **bold** or with _italics_ format as follows: + + **This text** is **bold** and _this one_ is with _italics_ + +#### Lists + +To define numbered lists, start your link with a number and a dot (.) and ensure there is a blank line before and after the list. The numbers are automatically generated so it does not matter what number you put: + + 1. list 1st item + 1. second item + 1. and so on + 1. and so forth + +To define bulleted lists, start your items with a hyphen (-) + + - item 1 + - item 2 + - item 3 + +To nest lists within one another, put four spaces to indent your inner list as follows: + + 1. item 1 + 1. item 2 + - sub item 1 + - sub item 2 + 1. item 3 + +#### Links (to other pages) + +Links to other pages can be defined by adding your text in box brackets [] followed by the link in round brackets () + + [This is an external link](http://example.com) + [A link within the site](my-page.html) + +#### Images + +Images can be added by adding an exclamation ! before the link. + + ![A flower](files/flower.gif) + + +#### Code + +To add a code block, just leave a blank line before and after the block and make sure all code line are indented by four spaces: + + This is normal text + + This is a code block + +#### HTML + +You can embed any kind of HTML tags within your code. Any content written within HTML tags will not be formatted. + +[Detailed description of the markdown format](http://daringfireball.net/projects/markdown/syntax) + + diff --git a/docs/user/knowledge/docs.user.knowledge.md b/docs/user/knowledge/docs.user.knowledge.md index 5d98cdd459..11dc9957ac 100644 --- a/docs/user/knowledge/docs.user.knowledge.md +++ b/docs/user/knowledge/docs.user.knowledge.md @@ -4,8 +4,12 @@ "_toc": [ "docs.user.knowledge.fiscal_year", "docs.user.knowledge.accounting", - "docs.user.knowledge.accounting_entries" + "docs.user.knowledge.accounting_entries", + "docs.user.knowledge.doctype", + "docs.user.knowledge.attachment_csv", + "docs.user.knowledge.markdown" ] } --- -Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge. \ No newline at end of file +Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge. + diff --git a/docs/user/selling/docs.user.selling.customer.md b/docs/user/selling/docs.user.selling.customer.md index 108f20da83..5336ac61a1 100644 --- a/docs/user/selling/docs.user.selling.customer.md +++ b/docs/user/selling/docs.user.selling.customer.md @@ -4,7 +4,9 @@ "_title_image": "img/customers.png" } --- -You can either directly create your Customers via +A customer, who is sometimes known as a client, buyer, or purchaser is the one who receives goods, services, products, or ideas, from a seller for a monetary consideration. A customer can also receive goods or services from a vendor or a supplier for other valuable considerations. + + You can either directly create your Customers via > Selling > Customer diff --git a/docs/user/setup/docs.user.setup.data_import.md b/docs/user/setup/docs.user.setup.data_import.md index eec6b65e45..b40573ed43 100644 --- a/docs/user/setup/docs.user.setup.data_import.md +++ b/docs/user/setup/docs.user.setup.data_import.md @@ -3,7 +3,7 @@ "_label": "Data Import Tool" } --- -The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To start the tool go to: +The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To Open the data import tool, you either go to Setup or go to the Transaction you want to Import. If Data Import is allowed, you will see an Import Button: @@ -15,7 +15,7 @@ The tool has two sections, one to download a template and the second to upload t ### 1. Downloading The Template -Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on. +Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where there are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on. You can import each table separately, or all at a time. In the child table, you must mention the parent of the row in the “parent” column so that ERPNext knows which Item’s price or tax you are trying to set if you are importing separately. @@ -36,7 +36,7 @@ Then export your template or save it as a **Comma Separated Values** (CSV) file. ### 3. Upload the .csv File -Finally attach the .csv file in the section section click on the "Upload and Import" button. +Finally attach the .csv file in the section. Click on the "Upload and Import" button. ![Attach and Upload](img/import-5.png) diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index c98afd29dd..5ac78d7e51 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -27,11 +27,7 @@ To upload an image for your icon that will appear in all transactions, save the ![Item Properties](img/item-add-image.png) -### Item Pricing - -Item Price and Price Lists: ERPNext lets you maintain multiple selling prices for an Item using Price Lists. A Price List is a place where different rate plans can be stored. It’s a name you can give to a set of Item prices. In case you have different zones (based on the shipping costs), for different currencies etc, you can maintain different Price Lists. A Price List is formed when you create different Item Prices. To import Item Price see [Importing Data](docs.user.data_import.md). - -## Inventory : Warehouse and Stock Setting +### Inventory : Warehouse and Stock Setting In ERPNext, you can select different type of Warehouses to stock your different Items. This can be selected based on Item types. It could be Fixed Asset Item, Stock Item or even Manufacturing Item. From d086d724b638a80e501abf4746ce3ebcab4c0e81 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 11:37:44 +0530 Subject: [PATCH 030/123] [price_list] new grid finished with fixes --- setup/doctype/price_list/price_list.js | 37 +++++--------------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 6dfbd0f1ee..0057773d57 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -12,8 +12,12 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { } cur_frm.cscript.show_item_prices = function() { - var counter = 0; var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); + var show = item_price && item_price.length; + + cur_frm.toggle_display("item_prices", show); + $(cur_frm.fields_dict.item_prices.wrapper).empty(); + if (!show) return; new wn.ui.form.TableGrid({ parent: cur_frm.fields_dict.item_prices.wrapper, @@ -159,7 +163,8 @@ wn.ui.form.TableGrid = Class.extend({ fields: this.fields }); - this.dialog.set_values(this.make_dialog_values(row)); + if (row) + this.dialog.set_values(this.make_dialog_values(row)); $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); this.dialog.show(); @@ -173,34 +178,6 @@ wn.ui.form.TableGrid = Class.extend({ }); return row; }, - // make_dialog_fields: function() { - // var me = this; - // var fields = []; - - // $.each(this.fields, function(i, obj) { - // var dialog_field = { - // fieldtype: obj.fieldtype, - // fieldname: obj.fieldname, - // label: obj.label - // } - - // // check if fields has options - // if (obj.options) { - // var options = {options: obj.options} - // $.extend(dialog_field, options); - // } - - // // check if field is mandatory - // if (obj.reqd == 1) { - // var reqd = {reqd: obj.reqd} - // $.extend(dialog_field, reqd); - // } - - // fields.push(obj); - // }); - - // return fields; - // }, make_dialog_values: function(row) { var me = this; var dialog_values = {}; From 7d36fc821bba65928c8a9537720fb119e6bb4122 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 12:44:00 +0530 Subject: [PATCH 031/123] [fix] [minor] new grid fix to hide other grid --- setup/doctype/price_list/price_list.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 0057773d57..a190710d4e 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -13,11 +13,9 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.show_item_prices = function() { var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); - var show = item_price && item_price.length; - - cur_frm.toggle_display("item_prices", show); + + cur_frm.toggle_display("item_prices", true); $(cur_frm.fields_dict.item_prices.wrapper).empty(); - if (!show) return; new wn.ui.form.TableGrid({ parent: cur_frm.fields_dict.item_prices.wrapper, From 9cb2cdbce6635d034eb09e05d8c09d2fcb7a88e4 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 15:43:00 +0530 Subject: [PATCH 032/123] [price_list] [minor] fix of new grid --- setup/doctype/price_list/price_list.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index a190710d4e..cbca413f0c 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -181,7 +181,7 @@ wn.ui.form.TableGrid = Class.extend({ var dialog_values = {}; $.each(this.fields, function(i, item) { - dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').attr('data-fieldvalue'); }); return dialog_values; @@ -206,9 +206,9 @@ wn.ui.form.TableGrid = Class.extend({ $.each(me.fields, function(i, item) { var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); var val = me.dialog.get_values()[item.fieldname]; - + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), - item.fieldname, me.dialog.get_values()[item.fieldname]); + item.fieldname, val); $td.attr('data-fieldvalue', val); // If field type is currency the update with format currency @@ -279,6 +279,10 @@ wn.ui.form.TableGrid = Class.extend({ } }); + // refresh field to push to grid rows + refresh_field(this.table_field.fieldname); + + // append row to tbody of grid $(new_row).appendTo($(this.parent).find(".grid tbody")); } }); \ No newline at end of file From eb8753e8b6419d6d50765d42975d3fcf800db078 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 15:56:36 +0530 Subject: [PATCH 033/123] [fix] [minor] new grid to hide delete button on new row & added description --- setup/doctype/price_list/price_list.js | 6 +++--- setup/doctype/price_list/price_list.txt | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index cbca413f0c..397e9826ad 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -164,7 +164,7 @@ wn.ui.form.TableGrid = Class.extend({ if (row) this.dialog.set_values(this.make_dialog_values(row)); - $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons()); + $a(this.dialog.body, 'div', '', '', this.make_dialog_buttons(row)); this.dialog.show(); this.dialog.$wrapper.find('button.update').on('click', function() { @@ -186,12 +186,12 @@ wn.ui.form.TableGrid = Class.extend({ return dialog_values; }, - make_dialog_buttons: function() { + make_dialog_buttons: function(row) { var me = this; var buttons = ''; // if user can delete then only add the delete button in dialog - if (wn.model.can_delete(me.frm.doc.doctype)) + if (wn.model.can_delete(me.frm.doc.doctype) && row) buttons += ' '; return buttons; diff --git a/setup/doctype/price_list/price_list.txt b/setup/doctype/price_list/price_list.txt index 46905a6591..343331dd0c 100644 --- a/setup/doctype/price_list/price_list.txt +++ b/setup/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-09-06 15:03:38", + "modified": "2013-09-30 15:50:52", "modified_by": "Administrator", "owner": "Administrator" }, @@ -85,6 +85,7 @@ "reqd": 1 }, { + "description": "To change row values, click on the respective row", "doctype": "DocField", "fieldname": "item_prices_section", "fieldtype": "Section Break", From 300ae0cdf4444129f789a4b45cb4037e890951d5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 30 Sep 2013 17:57:22 +0530 Subject: [PATCH 034/123] [fix] [minor] dont call is_pos trigger in onload of pos invoice --- accounts/doctype/sales_invoice/sales_invoice.js | 6 ++++-- accounts/doctype/sales_invoice/sales_invoice.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 6639e65e6c..4f8dda8fbe 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -29,8 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte // toggle to pos view if is_pos is 1 in user_defaults if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) && cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) { - this.frm.set_value("is_pos", 1); - this.is_pos(); + if(this.frm.doc.__islocal) { + this.frm.set_value("is_pos", 1); + this.is_pos(); + } cur_frm.cscript.toggle_pos(true); } diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 12deed73a8..2eb9ae84cb 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -195,7 +195,7 @@ class DocType(SellingController): pos = get_pos_settings(self.doc.company) if pos: - if not for_validate: + if not for_validate and not self.doc.customer: self.doc.customer = pos.customer self.set_customer_defaults() From cadc6e1b2be2563bd3afed150bd76d8313f7cb54 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 30 Sep 2013 17:57:37 +0530 Subject: [PATCH 035/123] [fix] [minor] dont call is_pos trigger in onload of pos invoice --- setup/doctype/price_list/price_list.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index a190710d4e..cbca413f0c 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -181,7 +181,7 @@ wn.ui.form.TableGrid = Class.extend({ var dialog_values = {}; $.each(this.fields, function(i, item) { - dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').data('fieldvalue'); + dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').attr('data-fieldvalue'); }); return dialog_values; @@ -206,9 +206,9 @@ wn.ui.form.TableGrid = Class.extend({ $.each(me.fields, function(i, item) { var $td = $(row).find('td[data-fieldname="'+ item.fieldname +'"]'); var val = me.dialog.get_values()[item.fieldname]; - + wn.model.set_value(me.table_field.options, $td.attr('data-doc_name'), - item.fieldname, me.dialog.get_values()[item.fieldname]); + item.fieldname, val); $td.attr('data-fieldvalue', val); // If field type is currency the update with format currency @@ -279,6 +279,10 @@ wn.ui.form.TableGrid = Class.extend({ } }); + // refresh field to push to grid rows + refresh_field(this.table_field.fieldname); + + // append row to tbody of grid $(new_row).appendTo($(this.parent).find(".grid tbody")); } }); \ No newline at end of file From 4233ae2258a1f60edb9e5cc331fc79312e2c08c8 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 18:18:19 +0530 Subject: [PATCH 036/123] [pos] pos related fixes --- accounts/doctype/sales_invoice/pos.js | 32 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index e19652d25f..0dba40fabc 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -214,7 +214,7 @@ erpnext.POS = Class.extend({ // if form is local then allow this function if (me.frm.doc.docstatus===0) { - $("div.pos-item").on("click", function() { + $(me.wrapper).find("div.pos-item").on("click", function() { if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { @@ -313,7 +313,7 @@ erpnext.POS = Class.extend({ // taxes var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges", this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype); - $(".tax-table") + $(this.wrapper).find(".tax-table") .toggle((taxes && taxes.length) ? true : false) .find("tbody").empty(); @@ -345,18 +345,18 @@ erpnext.POS = Class.extend({ // if form is local then only run all these functions if (this.frm.doc.docstatus===0) { - $("input.qty").on("focus", function() { + $(this.wrapper).find("input.qty").on("focus", function() { $(this).select(); }); // append quantity to the respective item after change from input box - $("input.qty").on("change", function() { + $(this.wrapper).find("input.qty").on("change", function() { var item_code = $(this).closest("tr")[0].id; me.update_qty(item_code, $(this).val(), true); }); // on td click toggle the highlighting of row - me.wrapper.find("#cart tbody tr td").on("click", function() { + $(this.wrapper).find("#cart tbody tr td").on("click", function() { var row = $(this).closest("tr"); if (row.attr("data-selected") == "false") { row.attr("class", "warning"); @@ -376,16 +376,22 @@ erpnext.POS = Class.extend({ // if form is submitted & cancelled then disable all input box & buttons if (this.frm.doc.docstatus>=1) { - me.wrapper.find('input, button').each(function () { + $(this.wrapper).find('input, button').each(function () { $(this).prop('disabled', true); }); - $(".delete-items").hide(); - $(".make-payment").hide(); + $(this.wrapper).find(".delete-items").hide(); + $(this.wrapper).find(".make-payment").hide(); + } + else { + $(this.wrapper).find('input, button').each(function () { + $(this).prop('disabled', false); + }); + $(this.wrapper).find(".make-payment").show(); } // Show Make Payment button only in Sales Invoice if (this.frm.doctype != "Sales Invoice") - $(".make-payment").hide(); + $(this.wrapper).find(".make-payment").hide(); // If quotation to is not Customer then remove party if (this.frm.doctype == "Quotation") { @@ -395,7 +401,7 @@ erpnext.POS = Class.extend({ } }, refresh_delete_btn: function() { - $(".delete-items").toggle($(".item-cart .warning").length ? true : false); + $(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false); }, add_item_thru_barcode: function() { var me = this; @@ -417,9 +423,9 @@ erpnext.POS = Class.extend({ remove_selected_item: function() { var me = this; var selected_items = []; - var no_of_items = me.wrapper.find("#cart tbody tr").length; + var no_of_items = $(this.wrapper).find("#cart tbody tr").length; for(var x=0; x<=no_of_items - 1; x++) { - var row = me.wrapper.find("#cart tbody tr:eq(" + x + ")"); + var row = $(this.wrapper).find("#cart tbody tr:eq(" + x + ")"); if(row.attr("data-selected") == "true") { selected_items.push(row.attr("id")); } @@ -442,7 +448,7 @@ erpnext.POS = Class.extend({ }, make_payment: function() { var me = this; - var no_of_items = me.wrapper.find("#cart tbody tr").length; + var no_of_items = $(this.wrapper).find("#cart tbody tr").length; var mode_of_payment = []; if (no_of_items == 0) From 67a9ea68008c6a73e89bdd18fd75d8b135714299 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 30 Sep 2013 19:05:36 +0530 Subject: [PATCH 037/123] [price_list] [minor] move header of new grid to right if currency --- setup/doctype/price_list/price_list.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 397e9826ad..2c24d7ec89 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -93,11 +93,16 @@ wn.ui.form.TableGrid = Class.extend({ // Make other headers with label as heading $.each(this.fields, function(i, obj) { - if (obj.in_list_view===1) - var th = document.createElement("th"); + var th = document.createElement("th"); + + // If currency then move header to right + if (obj.fieldtype == "Currency") + $(th).attr("style", "vertical-align:middle; text-align:right;"); + else $(th).attr("style", "vertical-align:middle"); - $(th).html(obj.label); - $(th).appendTo(row); + + $(th).html(obj.label); + $(th).appendTo(row); }); return header; From d780baeacc92c4c8c83fde464de75982a503f2cd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 11:22:51 +0530 Subject: [PATCH 038/123] [fix] [minor] fixes in old patch --- patches/august_2013/p02_rename_price_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/august_2013/p02_rename_price_list.py b/patches/august_2013/p02_rename_price_list.py index 41efb27306..0a1929925b 100644 --- a/patches/august_2013/p02_rename_price_list.py +++ b/patches/august_2013/p02_rename_price_list.py @@ -6,6 +6,7 @@ import webnotes def execute(): webnotes.reload_doc("selling", "doctype", "shopping_cart_price_list") + webnotes.reload_doc("setup", "doctype", "item_price") for t in [ ("Supplier Quotation", "price_list_name", "buying_price_list"), From 49e71400acfadfe0b14ec0ada1e4541ffddf88b0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 15:20:06 +0530 Subject: [PATCH 039/123] [patch] [minor] fix wrong customers in pos --- patches/patch_list.py | 1 + .../september_2013/p05_fix_customer_in_pos.py | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 patches/september_2013/p05_fix_customer_in_pos.py diff --git a/patches/patch_list.py b/patches/patch_list.py index 7041ba8858..6d1a084f68 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -218,4 +218,5 @@ patch_list = [ "execute:webnotes.bean('Style Settings').save() #2013-09-19", "execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24", "patches.september_2013.p04_unsubmit_serial_nos", + "patches.september_2013.p05_fix_customer_in_pos", ] \ No newline at end of file diff --git a/patches/september_2013/p05_fix_customer_in_pos.py b/patches/september_2013/p05_fix_customer_in_pos.py new file mode 100644 index 0000000000..60210dab24 --- /dev/null +++ b/patches/september_2013/p05_fix_customer_in_pos.py @@ -0,0 +1,22 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +def execute(): + si_list = webnotes.conn.sql("""select name, debit_to from `tabSales Invoice` + where ifnull(is_pos, 1)=1 and docstatus=1 and modified > '2013-09-03'""", as_dict=1) + + for si in si_list: + if not webnotes.conn.get_value("GL Entry", {"voucher_type": "Sales Invoice", + "voucher_no": si.name, "account": si.debit_to}): + debit_to = webnotes.conn.sql("""select account from `tabGL Entry` gle + where voucher_type='Sales Invoice' and voucher_no=%s + and (select master_type from tabAccount where name=gle.account)='Customer' + """, si.name) + if debit_to: + si_bean = webnotes.bean("Sales Invoice", si.name) + si_bean.doc.debit_to = debit_to[0][0] + si_bean.doc.customer = None + si_bean.run_method("set_customer_defaults") + si_bean.update_after_submit() \ No newline at end of file From b6177cbb5b38c88624eefb09f921e69d30157d41 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 1 Oct 2013 17:11:39 +0530 Subject: [PATCH 040/123] [minor] change filename to unicode after os.walk and os.listdir --- setup/doctype/backup_manager/backup_dropbox.py | 1 + setup/doctype/backup_manager/backup_googledrive.py | 1 + setup/doctype/company/charts/import_from_openerp.py | 2 ++ 3 files changed, 4 insertions(+) diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index 8d16353952..b4a8f66d4c 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -96,6 +96,7 @@ def backup_to_dropbox(): error_log = [] path = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(path): + filename = cstr(filename) if filename in ignore_list: continue diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py index 5d7b6ad0fa..440d907f2e 100644 --- a/setup/doctype/backup_manager/backup_googledrive.py +++ b/setup/doctype/backup_manager/backup_googledrive.py @@ -85,6 +85,7 @@ def backup_to_gdrive(): webnotes.conn.close() path = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(path): + filename = cstr(filename) found = False filepath = os.path.join(path, filename) ext = filename.split('.')[-1] diff --git a/setup/doctype/company/charts/import_from_openerp.py b/setup/doctype/company/charts/import_from_openerp.py index 894c2d739d..ef800086c9 100644 --- a/setup/doctype/company/charts/import_from_openerp.py +++ b/setup/doctype/company/charts/import_from_openerp.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals import os, json from xml.etree import ElementTree as ET from webnotes.utils.datautils import read_csv_content +from webnotes.utils import cstr path = "/Users/rmehta/Downloads/openerp/openerp/addons" chart_roots = [] @@ -108,6 +109,7 @@ def find_charts(): basename = os.path.basename(basepath) if basename.startswith("l10n"): for fname in files: + fname = cstr(fname) filepath = os.path.join(basepath, fname) if fname.endswith(".xml"): tree = ET.parse(filepath) From cf3011839f6ab28f9f1d75759bdd3c9fa30b8914 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Oct 2013 18:14:16 +0530 Subject: [PATCH 041/123] [fix] [minor] bind onclick function based on docstatus in pos --- accounts/doctype/sales_invoice/pos.js | 12 ++++++------ accounts/doctype/sales_invoice/sales_invoice.js | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js index 0dba40fabc..c68b9915c8 100644 --- a/accounts/doctype/sales_invoice/pos.js +++ b/accounts/doctype/sales_invoice/pos.js @@ -213,8 +213,8 @@ erpnext.POS = Class.extend({ }); // if form is local then allow this function - if (me.frm.doc.docstatus===0) { - $(me.wrapper).find("div.pos-item").on("click", function() { + $(me.wrapper).find("div.pos-item").on("click", function() { + if(me.frm.doc.docstatus==0) { if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" && me.frm.doc.quotation_to == "Customer") || me.frm.doctype != "Quotation")) { @@ -223,8 +223,8 @@ erpnext.POS = Class.extend({ } else me.add_to_cart($(this).attr("data-item_code")); - }); - } + } + }); } }); }, @@ -371,7 +371,7 @@ erpnext.POS = Class.extend({ }); me.refresh_delete_btn(); - this.frm.pos.barcode.$input.focus(); + this.barcode.$input.focus(); } // if form is submitted & cancelled then disable all input box & buttons @@ -476,7 +476,7 @@ erpnext.POS = Class.extend({ "total_amount": $(".grand-total").text() }); dialog.show(); - me.frm.pos.barcode.$input.focus(); + me.barcode.$input.focus(); dialog.get_input("total_amount").prop("disabled", true); diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 4f8dda8fbe..5220c0fa20 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -29,11 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte // toggle to pos view if is_pos is 1 in user_defaults if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) && cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) { - if(this.frm.doc.__islocal) { + if(this.frm.doc.__islocal && !this.frm.doc.amended_from) { this.frm.set_value("is_pos", 1); - this.is_pos(); + this.is_pos(function() {cur_frm.cscript.toggle_pos(true);}); } - cur_frm.cscript.toggle_pos(true); } // if document is POS then change default print format to "POS Invoice" @@ -128,7 +127,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte this.get_terms(); }, - is_pos: function() { + is_pos: function(callback_fn) { cur_frm.cscript.hide_fields(this.frm.doc); if(cint(this.frm.doc.is_pos)) { if(!this.frm.doc.company) { @@ -142,6 +141,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte callback: function(r) { if(!r.exc) { me.frm.script_manager.trigger("update_stock"); + if(callback_fn) callback_fn() } } }); From 2ebbe95e0464e0a273bdcd057ed3f69bc144ad8a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 2 Oct 2013 12:44:59 +0530 Subject: [PATCH 042/123] [minor] [fix] item prices html table --- setup/doctype/price_list/price_list.js | 248 ++++++++++-------------- setup/doctype/price_list/price_list.txt | 8 +- 2 files changed, 112 insertions(+), 144 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 2c24d7ec89..1dd9ec53de 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -14,46 +14,42 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.cscript.show_item_prices = function() { var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name}); - cur_frm.toggle_display("item_prices", true); - $(cur_frm.fields_dict.item_prices.wrapper).empty(); + $(cur_frm.fields_dict.item_prices_html.wrapper).empty(); new wn.ui.form.TableGrid({ - parent: cur_frm.fields_dict.item_prices.wrapper, + parent: cur_frm.fields_dict.item_prices_html.wrapper, frm: cur_frm, - table_field: wn.model.get("DocField", {parent:"Price List", fieldname:"item_prices"})[0] + table_field: wn.meta.get_docfield("Price List", "item_prices", cur_frm.doc.name) }); } wn.ui.form.TableGrid = Class.extend({ init: function(opts) { $.extend(this, opts); - this.fields = wn.model.get("DocField", {parent: this.table_field.options}); + this.fields = wn.meta.get_docfields("Item Price", cur_frm.doc.name); this.make_table(); }, make_table: function() { var me = this; // Creating table & assigning attributes var grid_table = document.createElement("table"); - $(grid_table).attr("class", "table table-hover table-bordered grid"); + grid_table.className = "table table-hover table-bordered grid"; // Appending header & rows to table - - $(this.make_table_headers()).appendTo(grid_table); - $(this.make_table_rows()).appendTo(grid_table); + grid_table.appendChild(this.make_table_headers()); + grid_table.appendChild(this.make_table_rows()); // Creating button to add new row var btn_div = document.createElement("div"); var new_row_btn = document.createElement("button"); - $new_row_btn = $(new_row_btn); - $new_row_btn.attr({ - "class": "btn btn-success table-new-row", - "title": "Add new row" - }); + new_row_btn.className = "btn btn-success table-new-row"; + new_row_btn.title = "Add new row"; + var btn_icon = document.createElement("i"); - $(btn_icon).attr("class", "icon-plus"); - $(btn_icon).appendTo(new_row_btn); - $new_row_btn.append(" Add new row"); - $new_row_btn.appendTo(btn_div); + btn_icon.className = "icon-plus"; + new_row_btn.appendChild(btn_icon); + new_row_btn.innerHTML += " Add new row"; + btn_div.appendChild(new_row_btn); // Appending table & button to parent var $grid_table = $(grid_table).appendTo($(this.parent)); @@ -75,35 +71,33 @@ wn.ui.form.TableGrid = Class.extend({ // Creating header row var row = document.createElement("tr"); - $(row).attr({ - "class": "active", - "style": "height:50px" - }); - $(row).appendTo(header); - + row.className = "active"; + // row.style = "height:50px"; + + // Creating head first cell var th = document.createElement("th"); - $(th).attr({ - "width": "8%", - "style": "vertical-align:middle", - "class": "text-center" - }); - $(th).html("#"); - $(th).appendTo(row); + th.width = "8%"; + th.className = "text-center"; + th.innerHTML = "#"; + row.appendChild(th); // Make other headers with label as heading - $.each(this.fields, function(i, obj) { - var th = document.createElement("th"); + for(var i=0, l=this.fields.length; i Date: Wed, 2 Oct 2013 14:25:36 +0530 Subject: [PATCH 043/123] Added Transactions for Import webnotes/erpnext#911 --- .../purchase_invoice/purchase_invoice.txt | 3 +- .../doctype/sales_invoice/sales_invoice.txt | 3 +- .../doctype/purchase_order/purchase_order.txt | 4 +- .../supplier_quotation/supplier_quotation.txt | 3 +- .../production_order/production_order.txt | 3 +- projects/doctype/project/project.txt | 3 +- projects/doctype/task/task.txt | 3 +- selling/doctype/lead/lead.txt | 136 ++++++++---------- selling/doctype/opportunity/opportunity.txt | 8 +- selling/doctype/quotation/quotation.txt | 6 +- selling/doctype/sales_order/sales_order.txt | 3 +- .../material_request/material_request.txt | 3 +- 12 files changed, 85 insertions(+), 93 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.txt b/accounts/doctype/purchase_invoice/purchase_invoice.txt index f5bdd939a8..8f772272b7 100755 --- a/accounts/doctype/purchase_invoice/purchase_invoice.txt +++ b/accounts/doctype/purchase_invoice/purchase_invoice.txt @@ -2,12 +2,13 @@ { "creation": "2013-05-21 16:16:39", "docstatus": 0, - "modified": "2013-08-09 14:45:35", + "modified": "2013-10-02 14:24:55", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "icon": "icon-file-text", diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index f921f24223..3c9075d9a5 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,12 +2,13 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-09-01 05:26:13", + "modified": "2013-10-02 14:24:52", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "naming_series:", "default_print_format": "Standard", "doctype": "DocType", diff --git a/buying/doctype/purchase_order/purchase_order.txt b/buying/doctype/purchase_order/purchase_order.txt index d3c1620b51..7169aaf390 100644 --- a/buying/doctype/purchase_order/purchase_order.txt +++ b/buying/doctype/purchase_order/purchase_order.txt @@ -2,12 +2,13 @@ { "creation": "2013-05-21 16:16:39", "docstatus": 0, - "modified": "2013-09-12 18:34:54", + "modified": "2013-10-02 14:24:49", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Transaction", @@ -132,7 +133,6 @@ "fieldtype": "Date", "in_filter": 1, "label": "Purchase Order Date", - "no_copy": 1, "oldfieldname": "transaction_date", "oldfieldtype": "Date", "reqd": 1, diff --git a/buying/doctype/supplier_quotation/supplier_quotation.txt b/buying/doctype/supplier_quotation/supplier_quotation.txt index 36747d345a..ddd17307dc 100644 --- a/buying/doctype/supplier_quotation/supplier_quotation.txt +++ b/buying/doctype/supplier_quotation/supplier_quotation.txt @@ -2,12 +2,13 @@ { "creation": "2013-05-21 16:16:45", "docstatus": 0, - "modified": "2013-08-09 14:45:58", + "modified": "2013-10-02 14:24:44", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Transaction", diff --git a/manufacturing/doctype/production_order/production_order.txt b/manufacturing/doctype/production_order/production_order.txt index 782c99f036..81821f6c45 100644 --- a/manufacturing/doctype/production_order/production_order.txt +++ b/manufacturing/doctype/production_order/production_order.txt @@ -2,11 +2,12 @@ { "creation": "2013-01-10 16:34:16", "docstatus": 0, - "modified": "2013-08-08 14:22:12", + "modified": "2013-10-02 14:25:03", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "icon": "icon-cogs", diff --git a/projects/doctype/project/project.txt b/projects/doctype/project/project.txt index 91dcfa1681..fc8accf1ee 100644 --- a/projects/doctype/project/project.txt +++ b/projects/doctype/project/project.txt @@ -2,12 +2,13 @@ { "creation": "2013-03-07 11:55:07", "docstatus": 0, - "modified": "2013-07-05 14:51:41", + "modified": "2013-10-02 14:25:02", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "field:project_name", "doctype": "DocType", "document_type": "Master", diff --git a/projects/doctype/task/task.txt b/projects/doctype/task/task.txt index d890bd67b9..1c12c8a534 100644 --- a/projects/doctype/task/task.txt +++ b/projects/doctype/task/task.txt @@ -2,12 +2,13 @@ { "creation": "2013-01-29 19:25:50", "docstatus": 0, - "modified": "2013-07-05 14:57:57", + "modified": "2013-10-02 14:25:00", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "TASK.#####", "doctype": "DocType", "document_type": "Master", diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index d96880bc75..9439e7854f 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,11 +2,12 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-09-19 10:38:58", + "modified": "2013-10-02 14:24:34", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Master", @@ -158,76 +159,8 @@ "doctype": "DocField", "fieldname": "communication_history", "fieldtype": "Section Break", - "label": "Communication", - "options": "icon-comments", - "print_hide": 1 - }, - { - "default": "__user", - "doctype": "DocField", - "fieldname": "lead_owner", - "fieldtype": "Link", - "in_filter": 1, - "label": "Lead Owner", - "oldfieldname": "lead_owner", - "oldfieldtype": "Link", - "options": "Profile", - "search_index": 1 - }, - { - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "col_break123", - "fieldtype": "Column Break", - "width": "50%" - }, - { - "allow_on_submit": 0, - "description": "Your sales person who will contact the lead in future", - "doctype": "DocField", - "fieldname": "contact_by", - "fieldtype": "Link", - "hidden": 0, - "in_filter": 1, - "label": "Next Contact By", - "oldfieldname": "contact_by", - "oldfieldtype": "Link", - "options": "Profile", - "print_hide": 0, - "reqd": 0, - "width": "100px" - }, - { - "allow_on_submit": 0, - "description": "Your sales person will get a reminder on this date to contact the lead", - "doctype": "DocField", - "fieldname": "contact_date", - "fieldtype": "Date", - "in_filter": 1, - "label": "Next Contact Date", - "no_copy": 1, - "oldfieldname": "contact_date", - "oldfieldtype": "Date", - "reqd": 0, - "width": "100px" - }, - { - "doctype": "DocField", - "fieldname": "sec_break123", - "fieldtype": "Section Break", - "options": "Simple" + "label": "Communication History", + "options": "icon-comments" }, { "allow_on_submit": 0, @@ -236,8 +169,7 @@ "fieldtype": "HTML", "label": "Communication HTML", "oldfieldname": "follow_up", - "oldfieldtype": "Table", - "print_hide": 1 + "oldfieldtype": "Table" }, { "doctype": "DocField", @@ -341,6 +273,18 @@ "oldfieldtype": "Select", "options": "\nClient\nChannel Partner\nConsultant" }, + { + "default": "__user", + "doctype": "DocField", + "fieldname": "lead_owner", + "fieldtype": "Link", + "in_filter": 1, + "label": "Lead Owner", + "oldfieldname": "lead_owner", + "oldfieldtype": "Link", + "options": "Profile", + "search_index": 1 + }, { "doctype": "DocField", "fieldname": "market_segment", @@ -402,6 +346,49 @@ "oldfieldtype": "Link", "options": "Quotation Lost Reason" }, + { + "allow_on_submit": 0, + "description": "Your sales person who will contact the lead in future", + "doctype": "DocField", + "fieldname": "contact_by", + "fieldtype": "Link", + "hidden": 0, + "in_filter": 1, + "label": "Next Contact By", + "oldfieldname": "contact_by", + "oldfieldtype": "Link", + "options": "Profile", + "print_hide": 0, + "reqd": 0, + "width": "100px" + }, + { + "allow_on_submit": 0, + "description": "Your sales person will get a reminder on this date to contact the lead", + "doctype": "DocField", + "fieldname": "contact_date", + "fieldtype": "Date", + "in_filter": 1, + "label": "Next Contact Date", + "no_copy": 1, + "oldfieldname": "contact_date", + "oldfieldtype": "Date", + "reqd": 0, + "width": "100px" + }, + { + "depends_on": "eval:!doc.__islocal", + "description": "Date on which the lead was last contacted", + "doctype": "DocField", + "fieldname": "last_contact_date", + "fieldtype": "Date", + "label": "Last Contact Date", + "no_copy": 1, + "oldfieldname": "last_contact_date", + "oldfieldtype": "Date", + "print_hide": 1, + "read_only": 1 + }, { "doctype": "DocField", "fieldname": "company", @@ -430,8 +417,7 @@ "fieldtype": "Table", "hidden": 1, "label": "Communications", - "options": "Communication", - "print_hide": 1 + "options": "Communication" }, { "cancel": 1, diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index a904f56643..d39b3efdae 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,11 +2,12 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-09-10 10:52:49", + "modified": "2013-10-02 14:24:35", "modified_by": "Administrator", "owner": "Administrator" }, { + "allow_import": 1, "autoname": "naming_series:", "description": "Potential Sales Deal", "doctype": "DocType", @@ -168,7 +169,6 @@ "label": "Communication History", "oldfieldtype": "Section Break", "options": "icon-comments", - "print_hide": 1, "read_only": 0 }, { @@ -179,7 +179,6 @@ "label": "Communication HTML", "oldfieldname": "follow_up", "oldfieldtype": "Table", - "print_hide": 1, "read_only": 0 }, { @@ -450,8 +449,7 @@ "fieldtype": "Table", "hidden": 1, "label": "Communications", - "options": "Communication", - "print_hide": 1 + "options": "Communication" }, { "doctype": "DocPerm", diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt index 3f97c980bc..200627f794 100644 --- a/selling/doctype/quotation/quotation.txt +++ b/selling/doctype/quotation/quotation.txt @@ -2,13 +2,14 @@ { "creation": "2013-05-24 19:29:08", "docstatus": 0, - "modified": "2013-09-10 10:46:33", + "modified": "2013-10-02 14:24:35", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, "allow_email": 0, + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Transaction", @@ -841,8 +842,7 @@ "fieldtype": "Table", "hidden": 1, "label": "Communications", - "options": "Communication", - "print_hide": 1 + "options": "Communication" }, { "amend": 1, diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt index 94e63888e3..366aa8e790 100644 --- a/selling/doctype/sales_order/sales_order.txt +++ b/selling/doctype/sales_order/sales_order.txt @@ -2,12 +2,13 @@ { "creation": "2013-06-18 12:39:59", "docstatus": 0, - "modified": "2013-08-09 14:46:17", + "modified": "2013-10-02 14:24:37", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Transaction", diff --git a/stock/doctype/material_request/material_request.txt b/stock/doctype/material_request/material_request.txt index a5f092d7cb..5fd576aab6 100644 --- a/stock/doctype/material_request/material_request.txt +++ b/stock/doctype/material_request/material_request.txt @@ -2,12 +2,13 @@ { "creation": "2013-03-07 14:48:38", "docstatus": 0, - "modified": "2013-08-08 14:22:27", + "modified": "2013-10-02 14:24:42", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_import": 1, "allow_print": 0, "autoname": "naming_series:", "doctype": "DocType", From 8c2e4e1e1f8892775e0afb77fe8f4002728a60be Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 2 Oct 2013 14:34:25 +0530 Subject: [PATCH 044/123] [wsgi] [minor] fixed webnotes.local.form_dict --- accounts/page/accounts_browser/accounts_browser.py | 2 +- accounts/utils.py | 4 ++-- hr/doctype/upload_attendance/upload_attendance.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accounts/page/accounts_browser/accounts_browser.py b/accounts/page/accounts_browser/accounts_browser.py index 61f4bfc521..7bc9549412 100644 --- a/accounts/page/accounts_browser/accounts_browser.py +++ b/accounts/page/accounts_browser/accounts_browser.py @@ -15,7 +15,7 @@ def get_companies(): @webnotes.whitelist() def get_children(): - args = webnotes.form_dict + args = webnotes.local.form_dict ctype, company = args['ctype'], args['comp'] # root diff --git a/accounts/utils.py b/accounts/utils.py index 5c6c16b76a..ac823129d6 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -108,7 +108,7 @@ def get_balance_on(account=None, date=None): @webnotes.whitelist() def add_ac(args=None): if not args: - args = webnotes.form_dict + args = webnotes.local.form_dict args.pop("cmd") ac = webnotes.bean(args) @@ -121,7 +121,7 @@ def add_ac(args=None): @webnotes.whitelist() def add_cc(args=None): if not args: - args = webnotes.form_dict + args = webnotes.local.form_dict args.pop("cmd") cc = webnotes.bean(args) diff --git a/hr/doctype/upload_attendance/upload_attendance.py b/hr/doctype/upload_attendance/upload_attendance.py index 5e2b02ea1f..56c8eedcc7 100644 --- a/hr/doctype/upload_attendance/upload_attendance.py +++ b/hr/doctype/upload_attendance/upload_attendance.py @@ -22,7 +22,7 @@ def get_template(): if not webnotes.has_permission("Attendance", "create"): raise webnotes.PermissionError - args = webnotes.form_dict + args = webnotes.local.form_dict webnotes.local.uploadattendance_doclist = webnotes.model.doctype.get("Attendance") w = UnicodeWriter() From 6f817b58ea7206865fd4c2a06d7921bd4bdcdec2 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 2 Oct 2013 15:16:22 +0530 Subject: [PATCH 045/123] [minor] [fix] item price grid --- setup/doctype/price_list/price_list.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index 1dd9ec53de..e1cb52130d 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -33,7 +33,7 @@ wn.ui.form.TableGrid = Class.extend({ var me = this; // Creating table & assigning attributes var grid_table = document.createElement("table"); - grid_table.className = "table table-hover table-bordered grid"; + grid_table.className = "table table-hover table-bordered table-grid"; // Appending header & rows to table grid_table.appendChild(this.make_table_headers()); @@ -72,8 +72,6 @@ wn.ui.form.TableGrid = Class.extend({ // Creating header row var row = document.createElement("tr"); row.className = "active"; - // row.style = "height:50px"; - // Creating head first cell var th = document.createElement("th"); @@ -106,7 +104,6 @@ wn.ui.form.TableGrid = Class.extend({ // Creating table body var table_body = document.createElement("tbody"); - table_body.style = "cursor: pointer"; var item_prices = wn.model.get_children(this.table_field.options, this.frm.doc.name, this.table_field.fieldname, this.frm.doctype); @@ -210,8 +207,7 @@ wn.ui.form.TableGrid = Class.extend({ $(row).remove(); // Re-assign idx - $.each($(this.parent).find(".grid tbody tr"), function(idx, data) { - $(data).attr("data-idx", idx + 1); + $.each($(this.parent).find("tbody tr"), function(idx, data) { var $td = $(data).find('td:first'); $td.html(idx + 1); }); @@ -221,7 +217,6 @@ wn.ui.form.TableGrid = Class.extend({ add_new_row: function(d) { var tr = document.createElement("tr"); tr.className = "table-row"; - tr.setAttribute("data-idx", d.idx); tr.setAttribute("data-docname", d.name); // Creating table data & appending to row From ea9f845814190e189e63e9b0692f17d2a02fba63 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 2 Oct 2013 16:02:02 +0530 Subject: [PATCH 046/123] feature to set / unset birthday reminders webnotes/erpnext#851 --- hr/doctype/employee/employee.py | 9 +++++---- hr/doctype/hr_settings/hr_settings.py | 20 +++++++++++++++++++- hr/doctype/hr_settings/hr_settings.txt | 21 ++++++++++++++++++++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index e8396eb539..b46123a6d1 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import getdate, validate_email_add, cstr +from webnotes.utils import getdate, validate_email_add, cstr, cint from webnotes.model.doc import make_autoname from webnotes import msgprint, _ @@ -39,12 +39,12 @@ class DocType: self.validate_email() self.validate_status() self.validate_employee_leave_approver() + self.update_dob_event() def on_update(self): if self.doc.user_id: self.update_user_default() self.update_profile() - self.update_dob_event() def update_user_default(self): webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id) @@ -155,10 +155,11 @@ class DocType: raise_exception=InvalidLeaveApproverError) def update_dob_event(self): - if self.doc.status == "Active" and self.doc.date_of_birth: + if self.doc.status == "Active" and self.doc.date_of_birth \ + and not cint(webnotes.conn.get_value("HR Settings", None, "stop_birthday_reminders")): birthday_event = webnotes.conn.sql("""select name from `tabEvent` where repeat_on='Every Year' and ref_type='Employee' and ref_name=%s""", self.doc.name) - + starts_on = self.doc.date_of_birth + " 00:00:00" ends_on = self.doc.date_of_birth + " 00:15:00" diff --git a/hr/doctype/hr_settings/hr_settings.py b/hr/doctype/hr_settings/hr_settings.py index 784339de7d..101905c57b 100644 --- a/hr/doctype/hr_settings/hr_settings.py +++ b/hr/doctype/hr_settings/hr_settings.py @@ -6,6 +6,24 @@ from __future__ import unicode_literals import webnotes +from webnotes.utils import cint + class DocType: def __init__(self, d, dl): - self.doc, self.doclist = d, dl \ No newline at end of file + self.doc, self.doclist = d, dl + + def validate(self): + self.original_stop_birthday_reminders = cint(webnotes.conn.get_value("HR Settings", + None, "stop_birthday_reminders")) + + def on_update(self): + # reset birthday reminders + if cint(self.doc.stop_birthday_reminders) != self.original_stop_birthday_reminders: + webnotes.conn.sql("""delete from `tabEvent` where repeat_on='Every Year' and ref_type='Employee'""") + + if not self.doc.stop_birthday_reminders: + for employee in webnotes.conn.sql_list("""select name from `tabEmployee` where status='Active' and + ifnull(date_of_birth, '')!=''"""): + webnotes.get_obj("Employee", employee).update_dob_event() + + webnotes.msgprint(webnotes._("Updated Birthday Reminders")) \ No newline at end of file diff --git a/hr/doctype/hr_settings/hr_settings.txt b/hr/doctype/hr_settings/hr_settings.txt index e3694d0572..bf4b0119aa 100644 --- a/hr/doctype/hr_settings/hr_settings.txt +++ b/hr/doctype/hr_settings/hr_settings.txt @@ -2,7 +2,7 @@ { "creation": "2013-08-02 13:45:23", "docstatus": 0, - "modified": "2013-08-02 14:22:26", + "modified": "2013-10-02 15:44:38", "modified_by": "Administrator", "owner": "Administrator" }, @@ -38,6 +38,12 @@ "doctype": "DocType", "name": "HR Settings" }, + { + "doctype": "DocField", + "fieldname": "employee_settings", + "fieldtype": "Section Break", + "label": "Employee Settings" + }, { "description": "Employee record is created using selected field. ", "doctype": "DocField", @@ -46,6 +52,19 @@ "label": "Employee Records to be created by", "options": "Naming Series\nEmployee Number" }, + { + "description": "Don't send Employee Birthday Reminders", + "doctype": "DocField", + "fieldname": "stop_birthday_reminders", + "fieldtype": "Check", + "label": "Stop Birthday Reminders" + }, + { + "doctype": "DocField", + "fieldname": "payroll_settings", + "fieldtype": "Section Break", + "label": "Payroll Settings" + }, { "description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day", "doctype": "DocField", From c49986f092ab145205adc47e3aeae6dd0da550e8 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 2 Oct 2013 16:14:30 +0530 Subject: [PATCH 047/123] [minor] [fix] price list table --- setup/doctype/price_list/price_list.css | 7 +++++++ setup/doctype/price_list/price_list.js | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 setup/doctype/price_list/price_list.css diff --git a/setup/doctype/price_list/price_list.css b/setup/doctype/price_list/price_list.css new file mode 100644 index 0000000000..61b069442f --- /dev/null +++ b/setup/doctype/price_list/price_list.css @@ -0,0 +1,7 @@ +.table-grid tbody tr { + cursor: pointer; +} + +.table-grid thead tr { + height: 50px; +} \ No newline at end of file diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js index e1cb52130d..67090bcbc1 100644 --- a/setup/doctype/price_list/price_list.js +++ b/setup/doctype/price_list/price_list.js @@ -188,6 +188,13 @@ wn.ui.form.TableGrid = Class.extend({ if(!docname && row) docname = $(row).attr("data-docname"); $.each(me.fields, function(i, df) { var val = me.dialog.get_values()[df.fieldname]; + + if(["Currency", "Float"].indexOf(df.fieldtype)!==-1) { + val = flt(val); + } else if(["Int", "Check"].indexOf(df.fieldtype)!==-1) { + val = cint(val); + } + wn.model.set_value(me.table_field.options, docname, df.fieldname, val); From a1d1c980bc041485f843f8899ab1504e4a315098 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 2 Oct 2013 16:29:45 +0530 Subject: [PATCH 048/123] [minor] fixes in stock balance report, bin uom and sle is_cancelled --- patches/october_2013/__init__.py | 0 patches/october_2013/fix_is_cancelled_in_sle.py | 13 +++++++++++++ patches/patch_list.py | 1 + public/js/stock_grid_report.js | 6 ++++-- stock/doctype/bin/bin.py | 2 +- .../stock_reconciliation/stock_reconciliation.py | 1 + stock/page/stock_balance/stock_balance.js | 7 ++++--- 7 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 patches/october_2013/__init__.py create mode 100644 patches/october_2013/fix_is_cancelled_in_sle.py diff --git a/patches/october_2013/__init__.py b/patches/october_2013/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/patches/october_2013/fix_is_cancelled_in_sle.py b/patches/october_2013/fix_is_cancelled_in_sle.py new file mode 100644 index 0000000000..050c1e68cd --- /dev/null +++ b/patches/october_2013/fix_is_cancelled_in_sle.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled = 'No' + where ifnull(is_cancelled, '') = ''""") + + webnotes.conn.sql("""update tabBin b set b.stock_uom = + (select i.stock_uom from tabItem i where i.name = b.item_code) + where b.created_on>='2013-09-01'""") \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 6d1a084f68..f228acf97e 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -219,4 +219,5 @@ patch_list = [ "execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24", "patches.september_2013.p04_unsubmit_serial_nos", "patches.september_2013.p05_fix_customer_in_pos", + "patches.october_2013.fix_is_cancelled_in_sle", ] \ No newline at end of file diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index 8b79b5e1ee..46370d27f6 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -29,6 +29,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ if(add_qty) wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); + + if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl); } else { // outgoing if(sl.serial_no) { @@ -98,7 +100,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ $.each(sl.serial_no.trim().split("\n"), function(i, sr) { if(sr) { - value_diff += flt(me.serialized_buying_rates[sr.trim()]); + value_diff += flt(me.serialized_buying_rates[sr.trim().toLowerCase()]); } }); @@ -112,7 +114,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ if(sle.qty > 0 && sle.serial_no) { $.each(sle.serial_no.trim().split("\n"), function(i, sr) { if(sr && sle.incoming_rate !== undefined) { - serialized_buying_rates[sr.trim()] = flt(sle.incoming_rate); + serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate); } }); } diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 788642fe4f..c419cad43b 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -16,7 +16,7 @@ class DocType: self.doclist = doclist def validate(self): - if not self.doc.stock_uom: + if self.doc.fields.get("__islocal") or not self.doc.stock_uom: self.doc.stock_uom = webnotes.conn.get_value('Item', self.doc.item_code, 'stock_uom') self.validate_mandatory() diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index 465edc490a..9feb57e716 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -246,6 +246,7 @@ class DocType(StockController): "stock_uom": webnotes.conn.get_value("Item", row.item_code, "stock_uom"), "voucher_detail_no": row.voucher_detail_no, "fiscal_year": self.doc.fiscal_year, + "is_cancelled": "No" }) args.update(opts) self.make_sl_entries([args]) diff --git a/stock/page/stock_balance/stock_balance.js b/stock/page/stock_balance/stock_balance.js index 1bc5d1c6bc..b45a610be8 100644 --- a/stock/page/stock_balance/stock_balance.js +++ b/stock/page/stock_balance/stock_balance.js @@ -126,10 +126,11 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ } else { item.inflow_value += value_diff; } - } - item.closing_qty += qty_diff; - item.closing_value += value_diff; + item.closing_qty += qty_diff; + item.closing_value += value_diff; + } + } else { break; } From efa94ce1bf092b7b4150aed1ca2ce1611fb7f203 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 2 Oct 2013 16:40:14 +0530 Subject: [PATCH 049/123] [fix] [minor] fixe in patch --- patches/october_2013/fix_is_cancelled_in_sle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/october_2013/fix_is_cancelled_in_sle.py b/patches/october_2013/fix_is_cancelled_in_sle.py index 050c1e68cd..cb51b5d7ca 100644 --- a/patches/october_2013/fix_is_cancelled_in_sle.py +++ b/patches/october_2013/fix_is_cancelled_in_sle.py @@ -10,4 +10,4 @@ def execute(): webnotes.conn.sql("""update tabBin b set b.stock_uom = (select i.stock_uom from tabItem i where i.name = b.item_code) - where b.created_on>='2013-09-01'""") \ No newline at end of file + where b.creation>='2013-09-01'""") \ No newline at end of file From f1b6f67a98c4877e7052e4cd13ff0112d3758237 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Oct 2013 12:22:52 +0530 Subject: [PATCH 050/123] [Delivery Note] Moved prevdoc to Sales Order and Sales Invoice so links will work webnotes/erpnext#868 --- .../doctype/sales_invoice/sales_invoice.py | 3 +- .../p01_update_delivery_note_prevdocs.py | 12 +++++ patches/patch_list.py | 1 + selling/doctype/sales_common/sales_common.py | 29 ++++++----- selling/doctype/sales_order/sales_order.py | 3 +- .../doctype/sales_order/test_sales_order.py | 3 +- stock/doctype/delivery_note/delivery_note.js | 10 ++-- stock/doctype/delivery_note/delivery_note.py | 49 ++++++++++--------- .../delivery_note_item/delivery_note_item.txt | 47 ++++++++---------- stock/doctype/stock_entry/stock_entry.py | 3 +- 10 files changed, 85 insertions(+), 75 deletions(-) create mode 100644 patches/october_2013/p01_update_delivery_note_prevdocs.py diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 2eb9ae84cb..1dca77b3fb 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -965,8 +965,7 @@ def make_delivery_note(source_name, target_doclist=None): "doctype": "Delivery Note Item", "field_map": { "name": "prevdoc_detail_docname", - "parent": "prevdoc_docname", - "parenttype": "prevdoc_doctype", + "parent": "against_sales_invoice", "serial_no": "serial_no" }, "postprocess": update_item diff --git a/patches/october_2013/p01_update_delivery_note_prevdocs.py b/patches/october_2013/p01_update_delivery_note_prevdocs.py new file mode 100644 index 0000000000..b1a16c28be --- /dev/null +++ b/patches/october_2013/p01_update_delivery_note_prevdocs.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_order=prevdoc_docname + where prevdoc_doctype='Sales Order' """) + + webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_invoice=prevdoc_docname + where prevdoc_doctype='Sales Invoice' """) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index f228acf97e..e19afdaf5c 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -220,4 +220,5 @@ patch_list = [ "patches.september_2013.p04_unsubmit_serial_nos", "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", + "patches.october_2013.p01_update_delivery_note_prevdocs", ] \ No newline at end of file diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py index 8271c82874..df7f151149 100644 --- a/selling/doctype/sales_common/sales_common.py +++ b/selling/doctype/sales_common/sales_common.py @@ -123,12 +123,12 @@ class DocType(TransactionBase): if flt(d.qty) > flt(d.delivered_qty): reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty) - if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order': + if obj.doc.doctype == "Delivery Note" and d.against_sales_order: # if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12. # But in this case reserved qty should only be reduced by 10 and not 12 already_delivered_qty = self.get_already_delivered_qty(obj.doc.name, - d.prevdoc_docname, d.prevdoc_detail_docname) + d.against_sales_order, d.prevdoc_detail_docname) so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname) if already_delivered_qty + d.qty > so_qty: @@ -168,7 +168,7 @@ class DocType(TransactionBase): def get_already_delivered_qty(self, dn, so, so_detail): qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item` where prevdoc_detail_docname = %s and docstatus = 1 - and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s + and against_sales_order = %s and parent != %s""", (so_detail, so, dn)) return qty and flt(qty[0][0]) or 0.0 @@ -218,7 +218,6 @@ class DocType(TransactionBase): pi.qty = flt(qty) pi.actual_qty = bin and flt(bin['actual_qty']) or 0 pi.projected_qty = bin and flt(bin['projected_qty']) or 0 - pi.prevdoc_doctype = line.prevdoc_doctype if not pi.warehouse: pi.warehouse = warehouse if not pi.batch_no: @@ -283,8 +282,8 @@ class DocType(TransactionBase): def check_stop_sales_order(self,obj): for d in getlist(obj.doclist,obj.fname): ref_doc_name = '' - if d.fields.has_key('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_doctype == 'Sales Order': - ref_doc_name = d.prevdoc_docname + if d.fields.has_key('against_sales_order') and d.against_sales_order: + ref_doc_name = d.against_sales_order elif d.fields.has_key('sales_order') and d.sales_order and not d.delivery_note: ref_doc_name = d.sales_order if ref_doc_name: @@ -321,14 +320,22 @@ class DocType(TransactionBase): def get_prevdoc_date(self, obj): for d in getlist(obj.doclist, obj.fname): - if d.prevdoc_doctype and d.prevdoc_docname: - if d.prevdoc_doctype in ["Sales Invoice", "Delivery Note"]: + date_field = None + + pdoctype, pname = d.prevdoc_doctype, d.prevdoc_docname + + if d.against_sales_invoice: + pdoctype, pname = "Sales Invoice", d.against_sales_invoice + elif d.against_sales_order: + pdoctype, pname = "Sales Order", d.against_sales_order + + if pdoctype and pname: + if pdoctype in ["Sales Invoice", "Delivery Note"]: date_field = "posting_date" else: date_field = "transaction_date" - - d.prevdoc_date = webnotes.conn.get_value(d.prevdoc_doctype, - d.prevdoc_docname, date_field) + + d.prevdoc_date = webnotes.conn.get_value(pdoctype, pname, date_field) def get_batch_no(doctype, txt, searchfield, start, page_len, filters): from controllers.queries import get_match_cond diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 40567429cc..8fc728fccd 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -341,8 +341,7 @@ def make_delivery_note(source_name, target_doclist=None): "field_map": { "export_rate": "export_rate", "name": "prevdoc_detail_docname", - "parent": "prevdoc_docname", - "parenttype": "prevdoc_doctype", + "parent": "against_sales_order", "reserved_warehouse": "warehouse" }, "postprocess": update_item, diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py index 7b72271bec..8bd759a77d 100644 --- a/selling/doctype/sales_order/test_sales_order.py +++ b/selling/doctype/sales_order/test_sales_order.py @@ -74,8 +74,7 @@ class TestSalesOrder(unittest.TestCase): from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0])) dn.doclist[1].item_code = so.doclist[1].item_code - dn.doclist[1].prevdoc_doctype = "Sales Order" - dn.doclist[1].prevdoc_docname = so.doc.name + dn.doclist[1].against_sales_order = so.doc.name dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name if delivered_qty: dn.doclist[1].qty = delivered_qty diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js index 84e65dabdd..edfd6ff7db 100644 --- a/stock/doctype/delivery_note/delivery_note.js +++ b/stock/doctype/delivery_note/delivery_note.js @@ -22,7 +22,7 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend( var from_sales_invoice = false; from_sales_invoice = cur_frm.get_doclist({parentfield: "delivery_note_details"}) .some(function(item) { - return item.prevdoc_doctype==="Sales Invoice" ? true : false; + return item.against_sales_invoice ? true : false; }); if(!from_sales_invoice) @@ -181,12 +181,12 @@ cur_frm.pformat.sales_order_no= function(doc, cdt, cdn){ if(cl.length){ prevdoc_list = new Array(); for(var i=0;i Date: Thu, 3 Oct 2013 13:19:51 +0530 Subject: [PATCH 051/123] [minor] [fix] [demo] --- utilities/demo/make_demo.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 4f30df62be..692ae31110 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -40,7 +40,9 @@ def make(reset=False, simulate=True): if reset: setup() else: - webnotes.conn.close() + if webnotes.conn: + webnotes.conn.close() + webnotes.connect(db_name=webnotes.conf.demo_db_name) if simulate: From 43247cedea3baf6928ff692ec44767c32df5afca Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Oct 2013 14:50:55 +0530 Subject: [PATCH 052/123] [issues] [minor] fixed multiple minor issues --- setup/doctype/sales_partner/sales_partner.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup/doctype/sales_partner/sales_partner.py b/setup/doctype/sales_partner/sales_partner.py index 79a59db71a..9e3e2a8235 100644 --- a/setup/doctype/sales_partner/sales_partner.py +++ b/setup/doctype/sales_partner/sales_partner.py @@ -11,6 +11,10 @@ class DocType: self.doc = doc self.doclist = doclist + def validate(self): + if self.doc.partner_website and not self.doc.partner_website.startswith("http"): + self.doc.partner_website = "http://" + self.doc.partner_website + def on_update(self): if cint(self.doc.show_in_website): from webnotes.webutils import update_page_name From 1859d9d49eb17862dc3ed0769f713445fe576ca4 Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 3 Oct 2013 16:54:26 +0530 Subject: [PATCH 053/123] [docs] 5 step setup folder added --- docs/user/docs.user.md | 7 +- .../five_step_setup/docs.user.five.day_1.md | 85 +++++++++++++++++++ .../five_step_setup/docs.user.five.day_2.md | 53 ++++++++++++ docs/user/five_step_setup/docs.user.five.md | 46 ++++++++++ .../setup/docs.user.setup.cost_centers.md | 8 ++ docs/user/setup/docs.user.setup.users.md | 2 +- docs/user/stock/docs.user.stock.item.md | 2 +- 7 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_1.md create mode 100644 docs/user/five_step_setup/docs.user.five.day_2.md create mode 100644 docs/user/five_step_setup/docs.user.five.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index c45ca30a22..82e211f1ce 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -3,6 +3,7 @@ "_label": "User Guide", "_toc": [ "docs.user.intro", + "docs.user.five", "docs.user.implement", "docs.user.setup", "docs.user.selling", @@ -17,7 +18,7 @@ "docs.user.tools", "docs.user.customize", "docs.user.knowledge" - ], + ], "_no_toc": 1 } --- @@ -29,6 +30,9 @@ Contents 1. [Open Source](docs.user.intro.open_source.html) 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) +1. [Five-Day-Setup](docs.user.five.html) + 1. [Day-1](docs.user.five.day_1.html) + 1. [Day-2](docs.user.five.day_2.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) @@ -154,4 +158,3 @@ Contents 1. [DocType Definitions](docs.user.knowledge.doctype.html) 1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html) 1. [Format using Markdown](docs.user.knowledge.markdown.html) - diff --git a/docs/user/five_step_setup/docs.user.five.day_1.md b/docs/user/five_step_setup/docs.user.five.day_1.md new file mode 100644 index 0000000000..d6786b40da --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_1.md @@ -0,0 +1,85 @@ +--- +{ + "_label": "Day-1" +} +--- +Login to your ERPNext account with the User ID and Password sent through the mail. + +After logging into your account you will receive a pop-up form to fill. Please fill this form. Select the abbreviation you would wish to have for your company. The abbreviation selected here will be used in naming most of the business documents. + +#### Form Part I + +![1st Form](img/firstdaysetup_1.png) +
+#### Form Part II +
+ +To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) + + +![1st Form](img/firstdaysetup_2.png) + +After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear. + +
+#### Setup Page - Customer + +The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon. + +![Customer](img/firstdaysetup_customer.png) +
+ + +After clicking on Customer, a new form will appear. +
+ +![Customer](img/firstdaysetup_customer_1.png) + +To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system. + +Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup + +![Main Menu](img/firstdaysetup_main_menu.png) + +
+ +#### Setup Page - Item + +On the setup page go to Item. + + +![Item](img/firstdaysetup_item.png) + + +Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers. + +Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item. + +![Item](img/firstdaysetup_item_1.png) + +To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers. + +
+#### Setup Page - Suppliers +
+ +On the Setup page go to Supplier. + +![Supplier](img/firstdaysetup_supplier.png) +
+ +Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record. + +![Supplier](img/firstdaysetup_supplier_1.png) + + +To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html). + +If you wish to import your list of customers and suppliers directly to ERPNext, you can do that via the Data Import Tool. + +To upload Customers or suppliers in bulk, go to the Data Import Tool. + +> Note: The data import format is case-sensitive. The file will not be processed if there are any spelling mistakes or deviations from the default values. + +To understand how to import data, visit [Importing Data](docs.user.setup.data_import.html). + diff --git a/docs/user/five_step_setup/docs.user.five.day_2.md b/docs/user/five_step_setup/docs.user.five.day_2.md new file mode 100644 index 0000000000..c1a5d28cb7 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_2.md @@ -0,0 +1,53 @@ +--- +{ + "_label": "Day-2" +} +--- + +#### Setup Page- Accounts + +Go to the Accounts icon and make ledgers under Chart of Accounts. + +![Accounts](img/seconddaysetup_accounts.png) + +
+ + +Create acccounting ledgers. + +![Tree](img/seconddaysetup_tree.png) + +
+ +To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. + +
+ +![Ledger](img/seconddaysetup_accounts_jv.png) + +
+ + +To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html). + +#### Opening Stock + +You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. + +![Stock Opening](img/seconddaysetup_stock_opening.png) +
+ + +To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html). + + +#### Setup Page - HR Setup + +To setup HR, begin by creating individual employee records. + + +![Employee](img/seconddaysetup_hr.png) + +To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html) + +To complete the remaining HR-Setup, see [Human Resources](docs.user.hr.html) \ No newline at end of file diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md new file mode 100644 index 0000000000..4203fad62a --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.md @@ -0,0 +1,46 @@ +--- +{ + "_label": "Five-Day Setup", + "_toc": [ + "docs.user.five.day_1", + "docs.user.five.day_2" + + ] +} +--- +Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation. + +The setup help is divided into day-wise instructions for 5 consecutive days. Day 1 will cover the following topics: + +#### Day 1 + +- Company Setup +- Customer Setup +- Item Setup +- Supplier Setup +- Data Import Tool + +#### Day 2 + +- Opening Accounts +- Opening Stock +- HR Setup + +#### Day 3 + +- Sales Cycle +- Purchase Cycle +- Manufacturing Cycle + + +#### Day 4 + +- Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc +- Accounts + +#### Day 5 + +- Billing +- Payments +- HR Reports + diff --git a/docs/user/setup/docs.user.setup.cost_centers.md b/docs/user/setup/docs.user.setup.cost_centers.md index 3df26e16a0..d666e4157f 100644 --- a/docs/user/setup/docs.user.setup.cost_centers.md +++ b/docs/user/setup/docs.user.setup.cost_centers.md @@ -45,6 +45,14 @@ ERPNext will help you set and manage budgets on your Cost Centers. This is usefu Budgets are also great for planning purposes. When you are making plans for the next financial year, you would typically target a revenue based on which you would set your expenses. Setting a budget will ensure that your expenses do not get out of hand, at any point, as per your plans. You can define it in the Cost Center. If you have seasonal sales you can also define a budget distribution that the budget will follow. + +> Accounts > Budget Distribution > New Budget Distribution + + +![Budget Distribution](img/budgeting.png) + + +  #### Budget Actions diff --git a/docs/user/setup/docs.user.setup.users.md b/docs/user/setup/docs.user.setup.users.md index 82d79d3d09..06ac9108ec 100644 --- a/docs/user/setup/docs.user.setup.users.md +++ b/docs/user/setup/docs.user.setup.users.md @@ -6,7 +6,7 @@ ERPNext has a role-based permission system, which means that you can assign Roles to Users, and permissions on Roles.Each ERPNext user has a Profile. The Profile contains the user’s email and authentication and can be set from: -> Setup > Users and Permissions > Users +> Setup > Profile #### Step 1: Adding a new User diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index 5ac78d7e51..76a83a2afa 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -15,7 +15,7 @@ ERPNext is optimized for itemized management of your sales and purchase. If you - **Item Name:** Item name is the actual name of your product or service. - **Item Code:** Item Code is a short-form to denote your Item. If you have very few Items, it is advisable to keep the Item Name and the Item Code same. This helps new users to recognise and update Item details in all transactions. In case you have lot of Items with long names and the list runs in hundreds, it is advisable to code. To understand naming Item codes see [Item Codification](docs.user.setup.codification.html) -- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under Item Group. +- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under [Item Group](docs.user.stock.item_group.html) - **Default Unit of Measure:** This is the default measuring unit that you will use for your product. It could be in nos, kgs, meters, etc. You can store all the UOM’s that your product will require under Set Up> Master Data > UOM. These can be preselected while filling New Item by using % sign to get a pop up of the UOM list. - **Brand:** If you have more than one brand save them under Set Up> Master Data> Brand and pre-select them while filling a New Item. From 800b3aa437aa0196f77c934f1443b4bff8b75ffb Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Oct 2013 17:26:33 +0530 Subject: [PATCH 054/123] [crm] Updated status and workflow for Lead > Opportunity > Quotation > Sales Order --- controllers/selling_controller.py | 5 +- controllers/status_updater.py | 78 +++++++++++++++++++ hr/doctype/job_applicant/job_applicant.py | 15 ++-- .../p02_set_communication_status.py | 9 +++ patches/october_2013/p03_crm_update_status.py | 32 ++++++++ patches/patch_list.py | 2 + selling/doctype/lead/lead.py | 27 ++----- selling/doctype/lead/lead.txt | 18 +---- selling/doctype/opportunity/opportunity.js | 15 +--- selling/doctype/opportunity/opportunity.py | 43 ++++------ selling/doctype/opportunity/opportunity.txt | 25 +++--- selling/doctype/quotation/quotation.js | 13 +--- selling/doctype/quotation/quotation.py | 64 +++++---------- selling/doctype/quotation/quotation.txt | 4 +- selling/doctype/sales_order/sales_order.js | 2 +- selling/doctype/sales_order/sales_order.py | 30 ++----- .../support_ticket/get_support_mails.py | 2 +- .../doctype/support_ticket/support_ticket.py | 13 +--- .../doctype/support_ticket/support_ticket.txt | 4 +- utilities/doctype/contact/contact.py | 9 +-- utilities/doctype/contact/contact.txt | 5 +- 21 files changed, 213 insertions(+), 202 deletions(-) create mode 100644 patches/october_2013/p02_set_communication_status.py create mode 100644 patches/october_2013/p03_crm_update_status.py diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index f1117ed177..2816524160 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -14,7 +14,10 @@ class SellingController(StockController): def onload_post_render(self): # contact, address, item details and pos details (if applicable) self.set_missing_values() - + + def get_sender(self, comm): + return webnotes.conn.get_value('Sales Email Settings', None, 'email_id') + def set_missing_values(self, for_validate=False): super(SellingController, self).set_missing_values(for_validate) diff --git a/controllers/status_updater.py b/controllers/status_updater.py index 070f200276..07b812a7dc 100644 --- a/controllers/status_updater.py +++ b/controllers/status_updater.py @@ -8,6 +8,51 @@ from webnotes import msgprint from webnotes.model.controller import DocListController +status_map = { + "Contact": [ + ["Replied", "communication_sent"], + ["Open", "communication_received"] + ], + "Job Applicant": [ + ["Replied", "communication_sent"], + ["Open", "communication_received"] + ], + "Lead": [ + ["Replied", "communication_sent"], + ["Converted", "has_customer"], + ["Opportunity", "has_opportunity"], + ["Open", "communication_received"], + ], + "Opportunity": [ + ["Draft", None], + ["Submitted", "eval:self.doc.docstatus==1"], + ["Lost", "eval:self.doc.status=='Lost'"], + ["Quotation", "has_quotation"], + ["Replied", "communication_sent"], + ["Cancelled", "eval:self.doc.docstatus==2"], + ["Open", "communication_received"], + ], + "Quotation": [ + ["Draft", None], + ["Submitted", "eval:self.doc.docstatus==1"], + ["Lost", "eval:self.doc.status=='Lost'"], + ["Ordered", "has_sales_order"], + ["Replied", "communication_sent"], + ["Cancelled", "eval:self.doc.docstatus==2"], + ["Open", "communication_received"], + ], + "Sales Order": [ + ["Draft", None], + ["Submitted", "eval:self.doc.docstatus==1"], + ["Stopped", "eval:self.doc.status=='Stopped'"], + ["Cancelled", "eval:self.doc.docstatus==2"], + ], + "Support Ticket": [ + ["Replied", "communication_sent"], + ["Open", "communication_received"] + ], +} + class StatusUpdater(DocListController): """ Updates the status of the calling records @@ -20,6 +65,39 @@ class StatusUpdater(DocListController): self.update_qty() self.validate_qty() + def set_status(self, update=False): + if self.doc.get("__islocal"): + return + + if self.doc.doctype in status_map.keys(): + for s in status_map[self.doc.doctype].reverse(): + if not s[1]: + self.doc.status = s[0] + break + elif s[1].startwith("eval:"): + if eval(s[1][5:]): + self.doc.status = s[0] + break + elif getattr(self, s[1])(): + self.doc.status = s[0] + break + + if update: + webnotes.conn.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status) + + def on_communication(self): + self.set_status(update=True) + + def communication_received(self): + last_comm = self.doclist.get({"doctype":"Communication"})[-1] + if last_comm: + return last_comm.sent_or_received == "Received" + + def communication_sent(self): + last_comm = self.doclist.get({"doctype":"Communication"})[-1] + if last_comm: + return last_comm.sent_or_received == "Sent" + def validate_qty(self): """ Validates qty at row level diff --git a/hr/doctype/job_applicant/job_applicant.py b/hr/doctype/job_applicant/job_applicant.py index 9bf1b967e7..0ab4ba8612 100644 --- a/hr/doctype/job_applicant/job_applicant.py +++ b/hr/doctype/job_applicant/job_applicant.py @@ -11,14 +11,9 @@ from webnotes.utils import extract_email_id class DocType(TransactionBase): def __init__(self, d, dl): self.doc, self.doclist = d, dl - + def get_sender(self, comm): - return webnotes.conn.get_value('Jobs Email Settings',None,'email_id') - - def on_communication(self, comm): - if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User": - status = "Replied" - else: - status = "Open" - - webnotes.conn.set(self.doc, 'status', status) \ No newline at end of file + return webnotes.conn.get_value('Jobs Email Settings',None,'email_id') + + def validate(self): + self.set_status() \ No newline at end of file diff --git a/patches/october_2013/p02_set_communication_status.py b/patches/october_2013/p02_set_communication_status.py new file mode 100644 index 0000000000..8360fe6cee --- /dev/null +++ b/patches/october_2013/p02_set_communication_status.py @@ -0,0 +1,9 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.conn.sql("""update tabCommunication + set sent_or_received= if(ifnull(recipients, '')='', "Received", "Sent")""") \ No newline at end of file diff --git a/patches/october_2013/p03_crm_update_status.py b/patches/october_2013/p03_crm_update_status.py new file mode 100644 index 0000000000..e5b434ce1f --- /dev/null +++ b/patches/october_2013/p03_crm_update_status.py @@ -0,0 +1,32 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +# reason field + +def execute(): + change_map = { + "Lead": [ + ["Lead Lost", "Lead"], + ["Not interested", "Do Not Contact"], + ["Opportunity Made", "Opportunity"], + ["Contacted", "Replied"], + ["Attempted to Contact", "Replied"], + ["Contact in Future", "Interested"], + ], + "Opportunity": [ + ["Quotation Sent", "Quotation"], + ["Order Confirmed", "Quotation"], + ["Opportunity Lost", "Lost"], + ], + "Quotation": [ + ["Order Confirmed", "Ordered"], + ["Order Lost", "Lost"] + ], + "Support Ticket": [ + ["Waiting for Customer", "Replied"], + ["To Reply", "Open"], + ] + } \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index e19afdaf5c..1596a2870b 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -221,4 +221,6 @@ patch_list = [ "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", "patches.october_2013.p01_update_delivery_note_prevdocs", + "patches.october_2013.p02_set_communication_status", + "patches.october_2013.p03_crm_update_status", ] \ No newline at end of file diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index 7a37446bf1..b42a380758 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -26,24 +26,9 @@ class DocType(SellingController): customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name}) if customer: self.doc.fields["__is_customer"] = customer - - def on_communication(self, comm): - if comm.sender == self.get_sender(comm) or \ - webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User": - status = "Replied" - else: - status = "Open" - - webnotes.conn.set(self.doc, 'status', status) - - def check_status(self): - chk = webnotes.conn.sql("select status from `tabLead` where name=%s", self.doc.name) - chk = chk and chk[0][0] or '' - return cstr(chk) def validate(self): - if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason: - webnotes.throw("Please Enter Lost Reason under More Info section") + self.set_status() if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest': webnotes.throw("Please specify campaign name") @@ -75,14 +60,18 @@ class DocType(SellingController): webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \ ", ".join(items), raise_exception=True) - def get_sender(self, comm): - return webnotes.conn.get_value('Sales Email Settings',None,'email_id') - def on_trash(self): webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""", self.doc.name) self.delete_events() + + def has_customer(self): + return webnotes.conn.get_value("Customer", {"lead_name": self.doc.name}) + + def has_opportunity(self): + return webnotes.conn.get_value("Opportunity", {"lead": self.doc.name, "docstatus": 1, + "status": ["!=", "Lost"]}) @webnotes.whitelist() def make_customer(source_name, target_doclist=None): diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index 6044f7994b..4f481b0a5e 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-10-02 14:24:30", + "modified": "2013-10-03 17:24:33", "modified_by": "Administrator", "owner": "Administrator" }, @@ -102,7 +102,7 @@ "fieldtype": "Column Break" }, { - "default": "Open", + "default": "Lead", "doctype": "DocField", "fieldname": "status", "fieldtype": "Select", @@ -112,7 +112,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive", + "options": "Lead\nOpen\nReplied\nOpportunity\nInterested\nConverted\nDo Not Contact", "reqd": 1, "search_index": 1 }, @@ -334,18 +334,6 @@ "oldfieldtype": "Column Break", "width": "50%" }, - { - "allow_on_submit": 0, - "depends_on": "eval:doc.status == 'Lead Lost'", - "doctype": "DocField", - "fieldname": "order_lost_reason", - "fieldtype": "Link", - "hidden": 0, - "label": "Lost Reason", - "oldfieldname": "order_lost_reason", - "oldfieldtype": "Link", - "options": "Quotation Lost Reason" - }, { "allow_on_submit": 0, "description": "Your sales person who will contact the lead in future", diff --git a/selling/doctype/opportunity/opportunity.js b/selling/doctype/opportunity/opportunity.js index 25f28bf3fb..d2b866cfbb 100644 --- a/selling/doctype/opportunity/opportunity.js +++ b/selling/doctype/opportunity/opportunity.js @@ -101,20 +101,13 @@ $.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm})); cur_frm.cscript.refresh = function(doc, cdt, cdn){ erpnext.hide_naming_series(); - - cur_frm.dashboard.reset(doc); - if(!doc.__islocal) { - if(doc.status=="Converted" || doc.status=="Order Confirmed") { - cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign"); - } else if(doc.status=="Opportunity Lost") { - cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign"); - } - } cur_frm.clear_custom_buttons(); - if(doc.docstatus === 1 && doc.status!=="Opportunity Lost") { + if(doc.docstatus === 1 && doc.status!=="Lost") { cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation); - cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']); + if(doc.status!=="Quotation") { + cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']); + } cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); } diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index e0be5fa957..e63ce6b060 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -6,7 +6,7 @@ import webnotes from webnotes.utils import cstr, getdate, cint from webnotes.model.bean import getlist -from webnotes import msgprint +from webnotes import msgprint, _ from utilities.transaction_base import TransactionBase @@ -67,7 +67,8 @@ class DocType(TransactionBase): 'email_id' : contact and contact[0]['email_id'] or '' } return ret - + + def on_update(self): # Add to calendar if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date: @@ -120,6 +121,7 @@ class DocType(TransactionBase): msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) def validate(self): + self.set_status() self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") @@ -127,42 +129,29 @@ class DocType(TransactionBase): from accounts.utils import validate_fiscal_year validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date") - self.doc.status = "Draft" def on_submit(self): - webnotes.conn.set(self.doc, 'status', 'Submitted') - if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted": - webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made") + if self.doc.lead: + webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True) def on_cancel(self): - chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) - if chk: - msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.") - raise Exception - else: - webnotes.conn.set(self.doc, 'status', 'Cancelled') - if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, - "status")!="Converted": - if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}): - status = "Contacted" - else: - status = "Open" - - webnotes.conn.set_value("Lead", self.doc.lead, "status", status) + if self.has_quotation(): + webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists")) + self.set_status(update=True) def declare_enquiry_lost(self,arg): - chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name) - if chk: - msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.") - raise Exception - else: - webnotes.conn.set(self.doc, 'status', 'Opportunity Lost') + if not self.has_quotation(): + webnotes.conn.set(self.doc, 'status', 'Lost') webnotes.conn.set(self.doc, 'order_lost_reason', arg) - return 'true' + else: + webnotes.throw(_("Cannot declare as lost, because Quotation has been made.")) def on_trash(self): self.delete_events() + def has_quotation(self): + return webnotes.conn.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1}) + @webnotes.whitelist() def make_quotation(source_name, target_doclist=None): from webnotes.model.mapper import get_mapped_doclist diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index 21eae5f723..02caea0a6d 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-10-02 14:24:30", + "modified": "2013-10-03 16:30:58", "modified_by": "Administrator", "owner": "Administrator" }, @@ -126,7 +126,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled", + "options": "Draft\nSubmitted\nQuotation\nLost\nCancelled\nReplied\nOpen", "read_only": 1, "reqd": 1 }, @@ -350,18 +350,6 @@ "options": "Campaign", "read_only": 0 }, - { - "depends_on": "eval:!doc.__islocal", - "doctype": "DocField", - "fieldname": "order_lost_reason", - "fieldtype": "Small Text", - "label": "Quotation Lost Reason", - "no_copy": 1, - "oldfieldname": "order_lost_reason", - "oldfieldtype": "Small Text", - "read_only": 1, - "report_hide": 0 - }, { "doctype": "DocField", "fieldname": "company", @@ -376,6 +364,15 @@ "reqd": 1, "search_index": 1 }, + { + "depends_on": "eval:!doc.__islocal", + "doctype": "DocField", + "fieldname": "order_lost_reason", + "fieldtype": "Text", + "label": "Lost Reason", + "no_copy": 1, + "read_only": 1 + }, { "doctype": "DocField", "fieldname": "column_break2", diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js index e20308f18e..05feed012b 100644 --- a/selling/doctype/quotation/quotation.js +++ b/selling/doctype/quotation/quotation.js @@ -24,19 +24,10 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({ }, refresh: function(doc, dt, dn) { this._super(doc, dt, dn); - - cur_frm.dashboard.reset(doc); - if(!doc.__islocal) { - if(doc.status=="Converted" || doc.status=="Order Confirmed") { - cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign"); - } else if(doc.status==="Order Lost") { - cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign"); - } - } - if(doc.docstatus == 1 && doc.status!=='Order Lost') { + if(doc.docstatus == 1 && doc.status!=='Lost') { cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']); - if(doc.status!=="Order Confirmed") { + if(doc.status!=="Ordered") { cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']); } cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms); diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 8a3bef10e9..697f805a2c 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -47,6 +47,11 @@ class DocType(SellingController): if not doc.fields.get(r): doc.fields[r] = res[r] + + def has_sales_order(self): + return webnotes.conn.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1}) + + # Re-calculates Basic Rate & amount based on Price List Selected # -------------------------------------------------------------- def get_adj_percent(self, arg=''): @@ -108,13 +113,7 @@ class DocType(SellingController): def validate(self): super(DocType, self).validate() - import utilities - if not self.doc.status: - self.doc.status = "Draft" - else: - utilities.validate_status(self.doc.status, ["Draft", "Submitted", - "Order Confirmed", "Order Lost", "Cancelled"]) - + self.set_status() self.set_last_contact_date() self.validate_order_type() self.validate_for_items() @@ -125,42 +124,22 @@ class DocType(SellingController): sales_com_obj.check_active_sales_items(self) sales_com_obj.validate_max_discount(self,'quotation_details') sales_com_obj.check_conversion_rate(self) - - - def on_update(self): - # Set Quotation Status - webnotes.conn.set(self.doc, 'status', 'Draft') - + #update enquiry #------------------ - def update_enquiry(self, flag): - prevdoc='' - for d in getlist(self.doclist, 'quotation_details'): - if d.prevdoc_docname: - prevdoc = d.prevdoc_docname - - if prevdoc: - if flag == 'submit': #on submit - webnotes.conn.sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc) - elif flag == 'cancel': #on cancel - webnotes.conn.sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc) - elif flag == 'order lost': #order lost - webnotes.conn.sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc) - elif flag == 'order confirm': #order confirm - webnotes.conn.sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc) + def update_opportunity(self): + for opportunity in self.doclist.get_distinct_values("prevdoc_docname"): + webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True) # declare as order lost #------------------------- def declare_order_lost(self, arg): - chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name) - if chk: - msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.") - raise Exception - else: - webnotes.conn.set(self.doc, 'status', 'Order Lost') + if not self.has_sales_order(): + webnotes.conn.set(self.doc, 'status', 'Lost') webnotes.conn.set(self.doc, 'order_lost_reason', arg) - self.update_enquiry('order lost') - return 'true' + self.update_opportunity() + else: + webnotes.throw(_("Cannot set as Lost as Sales Order is made.")) #check if value entered in item table #-------------------------------------- @@ -176,21 +155,17 @@ class DocType(SellingController): # Check for Approving Authority get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self) - - # Set Quotation Status - webnotes.conn.set(self.doc, 'status', 'Submitted') - + #update enquiry status - self.update_enquiry('submit') + self.update_opportunity() # ON CANCEL # ========================================================================== def on_cancel(self): #update enquiry status - self.update_enquiry('cancel') - - webnotes.conn.set(self.doc,'status','Cancelled') + self.set_status() + self.update_opportunity() # Print other charges # =========================================================================== @@ -202,6 +177,7 @@ class DocType(SellingController): lst1.append(d.total) print_lst.append(lst1) return print_lst + @webnotes.whitelist() def make_sales_order(source_name, target_doclist=None): diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt index 200627f794..8a8b24ba44 100644 --- a/selling/doctype/quotation/quotation.txt +++ b/selling/doctype/quotation/quotation.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:08", "docstatus": 0, - "modified": "2013-10-02 14:24:35", + "modified": "2013-10-03 16:31:55", "modified_by": "Administrator", "owner": "Administrator" }, @@ -734,7 +734,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nDraft\nSubmitted\nOrder Confirmed\nOrder Lost\nCancelled", + "options": "Draft\nSubmitted\nOrdered\nLost\nCancelled", "print_hide": 1, "read_only": 1, "reqd": 1, diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index 0c261793e1..bf23b9cb9d 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -66,7 +66,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( source_doctype: "Quotation", get_query_filters: { docstatus: 1, - status: ["!=", "Order Lost"], + status: ["!=", "Lost"], order_type: cur_frm.doc.order_type, customer: cur_frm.doc.customer || undefined, company: cur_frm.doc.company diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 8fc728fccd..d3ac7ad339 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -165,36 +165,20 @@ class DocType(SellingController): }) - def check_prev_docstatus(self): - for d in getlist(self.doclist, 'sales_order_details'): - cancel_quo = webnotes.conn.sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname) - if cancel_quo: - msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !") - raise Exception , "Validation Error. " - def update_enquiry_status(self, prevdoc, flag): enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc) if enq: webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0])) - def update_prevdoc_status(self, flag): - for d in getlist(self.doclist, 'sales_order_details'): - if d.prevdoc_docname: - if flag=='submit': - webnotes.conn.sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname) - - #update enquiry - self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed') - elif flag == 'cancel': - chk = webnotes.conn.sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name)) - if not chk: - webnotes.conn.sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname) - - #update enquiry - self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent') + def update_prevdoc_status(self, flag): + for quotation in self.doclist.get_distinct_values("prevdoc_docname"): + bean = webnotes.bean("Quotation", quotation) + if bean.doc.docstatus==2: + webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled.")) + + bean.get_controller().set_status(update=True) def on_submit(self): - self.check_prev_docstatus() self.update_stock_ledger(update_stock = 1) get_obj('Sales Common').check_credit(self,self.doc.grand_total) diff --git a/support/doctype/support_ticket/get_support_mails.py b/support/doctype/support_ticket/get_support_mails.py index 4dcb59e4fe..4b61352fae 100644 --- a/support/doctype/support_ticket/get_support_mails.py +++ b/support/doctype/support_ticket/get_support_mails.py @@ -54,7 +54,7 @@ Original Query: def auto_close_tickets(self): webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed' - where status = 'Waiting for Customer' + where status = 'Replied' and date_sub(curdate(),interval 15 Day) > modified""") def get_support_mails(): diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py index bf2a9fbabe..eb68ff3bea 100644 --- a/support/doctype/support_ticket/support_ticket.py +++ b/support/doctype/support_ticket/support_ticket.py @@ -14,7 +14,7 @@ class DocType(TransactionBase): def get_sender(self, comm): return webnotes.conn.get_value('Email Settings',None,'support_email') - + def get_subject(self, comm): return '[' + self.doc.name + '] ' + (comm.subject or 'No Subject Specified') @@ -35,16 +35,7 @@ class DocType(TransactionBase): if self.doc.status == "Closed": from webnotes.widgets.form.assign_to import clear clear(self.doc.doctype, self.doc.name) - - def on_communication(self, comm): - if comm.sender == self.get_sender(comm) or \ - webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User": - self.doc.status = "Waiting for Customer" - else: - self.doc.status = "Open" - self.update_status() - self.doc.save() - + def set_lead_contact(self, email_id): import email.utils email_id = email.utils.parseaddr(email_id) diff --git a/support/doctype/support_ticket/support_ticket.txt b/support/doctype/support_ticket/support_ticket.txt index 9f385b2d25..76d9dcfb1e 100644 --- a/support/doctype/support_ticket/support_ticket.txt +++ b/support/doctype/support_ticket/support_ticket.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-01 10:36:25", "docstatus": 0, - "modified": "2013-09-10 10:54:02", + "modified": "2013-10-03 16:45:41", "modified_by": "Administrator", "owner": "Administrator" }, @@ -71,7 +71,7 @@ "no_copy": 1, "oldfieldname": "status", "oldfieldtype": "Select", - "options": "\nOpen\nTo Reply\nWaiting for Customer\nHold\nClosed", + "options": "Open\nReplied\nHold\nClosed", "read_only": 0, "reqd": 0, "search_index": 1 diff --git a/utilities/doctype/contact/contact.py b/utilities/doctype/contact/contact.py index 58437f1a62..db233fb68d 100644 --- a/utilities/doctype/contact/contact.py +++ b/utilities/doctype/contact/contact.py @@ -12,14 +12,6 @@ class DocType(TransactionBase): self.doc = doc self.doclist = doclist - def on_communication(self, comm): - if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User": - status = "Replied" - else: - status = "Open" - - webnotes.conn.set(self.doc, 'status', status) - def autoname(self): # concat first and last name self.doc.name = " ".join(filter(None, @@ -32,6 +24,7 @@ class DocType(TransactionBase): break def validate(self): + self.set_status() self.validate_primary_contact() def validate_primary_contact(self): diff --git a/utilities/doctype/contact/contact.txt b/utilities/doctype/contact/contact.txt index 92dcf2ef02..db23410820 100644 --- a/utilities/doctype/contact/contact.txt +++ b/utilities/doctype/contact/contact.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-10 16:34:32", "docstatus": 0, - "modified": "2013-09-10 10:50:27", + "modified": "2013-10-03 16:44:08", "modified_by": "Administrator", "owner": "Administrator" }, @@ -70,11 +70,12 @@ "fieldtype": "Column Break" }, { + "default": "Passive", "doctype": "DocField", "fieldname": "status", "fieldtype": "Select", "label": "Status", - "options": "\nOpen\nReplied" + "options": "Passive\nOpen\nReplied" }, { "doctype": "DocField", From 6856d74a1bc463e682ecc178f213d82acb0e7ac6 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Oct 2013 18:12:36 +0530 Subject: [PATCH 055/123] [minor] fixes to crm patch --- controllers/status_updater.py | 16 +++++++++------- .../p01_update_delivery_note_prevdocs.py | 1 + patches/october_2013/p03_crm_update_status.py | 17 ++++++++++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/controllers/status_updater.py b/controllers/status_updater.py index 07b812a7dc..e457fa957e 100644 --- a/controllers/status_updater.py +++ b/controllers/status_updater.py @@ -69,12 +69,14 @@ class StatusUpdater(DocListController): if self.doc.get("__islocal"): return - if self.doc.doctype in status_map.keys(): - for s in status_map[self.doc.doctype].reverse(): + if self.doc.doctype in status_map: + sl = status_map[self.doc.doctype][:] + sl.reverse() + for s in sl: if not s[1]: self.doc.status = s[0] break - elif s[1].startwith("eval:"): + elif s[1].startswith("eval:"): if eval(s[1][5:]): self.doc.status = s[0] break @@ -89,14 +91,14 @@ class StatusUpdater(DocListController): self.set_status(update=True) def communication_received(self): - last_comm = self.doclist.get({"doctype":"Communication"})[-1] + last_comm = self.doclist.get({"doctype":"Communication"}) if last_comm: - return last_comm.sent_or_received == "Received" + return last_comm[-1].sent_or_received == "Received" def communication_sent(self): - last_comm = self.doclist.get({"doctype":"Communication"})[-1] + last_comm = self.doclist.get({"doctype":"Communication"}) if last_comm: - return last_comm.sent_or_received == "Sent" + return last_comm[-1].sent_or_received == "Sent" def validate_qty(self): """ diff --git a/patches/october_2013/p01_update_delivery_note_prevdocs.py b/patches/october_2013/p01_update_delivery_note_prevdocs.py index b1a16c28be..75ac53f983 100644 --- a/patches/october_2013/p01_update_delivery_note_prevdocs.py +++ b/patches/october_2013/p01_update_delivery_note_prevdocs.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import webnotes def execute(): + webnotes.reload_doc("stock", "doctype", "delivery_note_item") webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_order=prevdoc_docname where prevdoc_doctype='Sales Order' """) diff --git a/patches/october_2013/p03_crm_update_status.py b/patches/october_2013/p03_crm_update_status.py index e5b434ce1f..73ed1b1c78 100644 --- a/patches/october_2013/p03_crm_update_status.py +++ b/patches/october_2013/p03_crm_update_status.py @@ -29,4 +29,19 @@ def execute(): ["Waiting for Customer", "Replied"], ["To Reply", "Open"], ] - } \ No newline at end of file + } + + for dt, opts in change_map.items(): + for status in opts: + webnotes.conn.sql("""update `tab%s` set status=%s where status=%s""" % \ + (dt, "%s", "%s"), (status[1], status[0])) + + # for dt in ["Lead", "Opportunity"]: + # for name in webnotes.conn.sql_list("""select name from `tab%s`""" % dt): + # bean = webnotes.bean(dt, name) + # before_status = bean.doc.status + # bean.get_controller().set_status() + # + # if bean.doc.status != before_status: + # webnotes.conn.sql("""update `tab%s` set status=%s where name=%s""" % (dt, "%s", "%s"), + # (bean.doc.status, name)) From d1809e30e9e81fa468792b1407e7b3f0082048db Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 3 Oct 2013 18:58:11 +0530 Subject: [PATCH 056/123] [minor] [fix] due date in sales invoice --- accounts/doctype/sales_invoice/sales_invoice.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 00c6c2cc5c..516d1925a8 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-09-19 11:42:13", + "modified": "2013-10-03 18:54:31", "modified_by": "Administrator", "owner": "Administrator" }, @@ -180,7 +180,6 @@ "search_index": 1 }, { - "default": "Today", "description": "Enter the date by which payments from customer is expected against this invoice.", "doctype": "DocField", "fieldname": "due_date", From 3ab6a6574337541fd03b22bf67d9ab36d3a484e0 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 3 Oct 2013 19:32:23 +0530 Subject: [PATCH 057/123] [minor] [fix] communication status patch --- patches/october_2013/p02_set_communication_status.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/patches/october_2013/p02_set_communication_status.py b/patches/october_2013/p02_set_communication_status.py index 8360fe6cee..d67d08dbe0 100644 --- a/patches/october_2013/p02_set_communication_status.py +++ b/patches/october_2013/p02_set_communication_status.py @@ -5,5 +5,7 @@ from __future__ import unicode_literals import webnotes def execute(): + webnotes.reload_doc("core", "doctype", "communication") + webnotes.conn.sql("""update tabCommunication set sent_or_received= if(ifnull(recipients, '')='', "Received", "Sent")""") \ No newline at end of file From b4212a5672d7f9651f568b19aa7cae679639ae97 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 12:54:16 +0530 Subject: [PATCH 058/123] [patch] [minor] perpetua inventory utility patch --- ...petual_inventory_stock_transfer_utility.py | 71 +++++++++++++++++++ .../set_stock_value_diff_in_sle.py | 10 +++ 2 files changed, 81 insertions(+) create mode 100644 patches/october_2013/perpetual_inventory_stock_transfer_utility.py create mode 100644 patches/october_2013/set_stock_value_diff_in_sle.py diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py new file mode 100644 index 0000000000..f59ebdb55b --- /dev/null +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -0,0 +1,71 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import nowdate, nowtime +from accounts.utils import get_fiscal_year + +def execute(): + item_map = {} + for item in webnotes.conn.sql("""select * from tabItem""", as_dict=1): + item_map.setdefault(item.name, item) + + warehouse_map = get_warehosue_map() + # naming_series = + for company in webnotes.conn.sql("select name from tabCompany"): + stock_entry = [{ + "doctype": "Stock Entry", + "naming_series": naming_series, + "posting_date": nowdate(), + "posting_time": nowtime(), + "purpose": "Material Transfer", + "company": company[0], + "remarks": "Material Transfer to activate perpetual inventory", + "fiscal_year": get_fiscal_year(nowdate()) + }] + expense_account = "Cost of Goods Sold - NISL" + cost_center = "Default CC Ledger - NISL" + + for bin in webnotes.conn.sql("select * from tabBin where company=%s", company[0] as_dict=1): + new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ + if cstr(item_map[bin.item_code]) == "Yes" else wh.get("current_asset_warehouse") + + item_details = item_map[bin.item_code] + stock_entry.append({ + "doctype": "Stock Entry Detail", + "parentfield": "mtn_details", + "s_warehouse": bin.warehouse, + "t_warehouse": new_warehouse, + "item_code": bin.item_code, + "description": item_details.description, + "qty": bin.actual_qty, + "transfer_qty": bin.actual_qty, + "uom": item_details.stock_uom, + "stock_uom": item_details.stock_uom, + "conversion_factor": 1, + "expense_account": expense_account, + "cost_center": cost_center + }) + + webnotes.bean(stock_entry).insert() + +def get_warehosue_map(): + return { + "MAHAPE": { + "current_asset_warehouse": "Mahape-New - NISL", + "fixed_asset_warehouse": "" + }, + "DROP SHIPMENT": { + "current_asset_warehouse": "Drop Shipment-New - NISL", + "fixed_asset_warehouse": "" + }, + "TRANSIT": { + "current_asset_warehouse": "Transit-New - NISL", + "fixed_asset_warehouse": "" + }, + "ASSET-MAHAPE": { + "current_asset_warehouse": "", + "fixed_asset_warehouse": "Assets-New - NISL" + } + } \ No newline at end of file diff --git a/patches/october_2013/set_stock_value_diff_in_sle.py b/patches/october_2013/set_stock_value_diff_in_sle.py new file mode 100644 index 0000000000..25f95e0e6d --- /dev/null +++ b/patches/october_2013/set_stock_value_diff_in_sle.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import cint + +def execute(): + from patches.september_2012 import repost_stock + repost_stock.execute() \ No newline at end of file From de4f8e692963d437cccfc7cca4680037b1238f1c Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 4 Oct 2013 13:20:39 +0530 Subject: [PATCH 059/123] [minor] [demo] fixed Lead.csv --- utilities/demo/demo_docs/Lead.csv | 134 +++++++++++++++--------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/utilities/demo/demo_docs/Lead.csv b/utilities/demo/demo_docs/Lead.csv index c00ab44162..a97fe3bacb 100644 --- a/utilities/demo/demo_docs/Lead.csv +++ b/utilities/demo/demo_docs/Lead.csv @@ -1,68 +1,68 @@ -Data Import Template,,,,,,,,,,,,,,,,,,,,,,,,,,, +Data Import Template,,,,,,,,,,,,,,,,,,,,,,,,,, Table:,Lead,,,,,,,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,,,,,,,, -Notes:,,,,,,,,,,,,,,,,,,,,,,,,,,, -Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,,,,,,,, -First data column must be blank.,,,,,,,,,,,,,,,,,,,,,,,,,,, -Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,,,,,,,, -"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,,,,,,,, -"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,,,,,,,, -"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,,,,,,, -You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,,,,,,, -,,,,,,,,,,,,,,,,,,,,,,,,,,, -Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Lost Reason,Next Contact By,Next Contact Date,Last Contact Date,Company,Unsubscribed,Blog Subscriber -Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,order_lost_reason,contact_by,contact_date,last_contact_date,company,unsubscribed,blog_subscriber -Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No -Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Link,Date,Date,Link,Check,Check -Info:,,,"One of: Open, Replied, Attempted to Contact, Contact in Future, Contacted, Interested, Not interested, Lead Lost, Converted","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Quotation Lost Reason,Valid Profile,,,Valid Company,0 or 1,0 or 1 -Start entering data below this line,,,,,,,,,,,,,,,,,,,,,,,,,,, -,,Mart Lakeman,Passive,,Zany Brainy,MartLakeman@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Saga Lundqvist,Passive,,Patterson-Fletcher,SagaLundqvist@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,Adna Sjöberg,Passive,,Griff's Hamburgers,AdnaSjoberg@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Ida Svendsen,Passive,,Rhodes Furniture,IdaDSvendsen@superrito.com,,,,,,,,,,,,,,,,,,,,, -,,Emppu Hämeenniemi,Passive,,Burger Chef,EmppuHameenniemi@teleworm.us,,,,,,,,,,,,,,,,,,,,, -,,Eugenio Pisano,Passive,,Stratabiz,EugenioPisano@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Semhar Hagos,Passive,,Home Quarters Warehouse,SemharHagos@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Branimira Ivanković,Passive,,Enviro Architectural Designs,BranimiraIvankovic@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Shelly Fields,Passive,,Ideal Garden Management,ShellyLFields@superrito.com,,,,,,,,,,,,,,,,,,,,, -,,Leo Mikulić,Passive,,Listen Up,LeoMikulic@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Denisa Jarošová,Passive,,I. Magnin,DenisaJarosova@teleworm.us,,,,,,,,,,,,,,,,,,,,, -,,Janek Rutkowski,Passive,,First Rate Choice,JanekRutkowski@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,美月 宇藤,Passive,,Multi Tech Development,mm@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Даниил Афанасьев,Passive,,National Auto Parts,dd@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Zorislav Petković,Passive,,Integra Investment Plan,ZorislavPetkovic@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Nanao Niwa,Passive,,The Lawn Guru,NanaoNiwa@superrito.com,,,,,,,,,,,,,,,,,,,,, -,,Hreiðar Jörundsson,Passive,,Buena Vista Realty Service,HreiarJorundsson@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Lai Chu,Passive,,Bountiful Harvest Health Food Store,ChuThiBichLai@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Victor Aksakov,Passive,,P. Samuels Men's Clothiers,VictorAksakov@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,Saidalim Bisliev,Passive,,Vinyl Fever,SaidalimBisliev@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Totte Jakobsson,Passive,,Garden Master,TotteJakobsson@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Naná Armas,Passive,,Big Apple,NanaArmasRobles@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Walerian Duda,Passive,,Monk House Sales,WalerianDuda@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,Moarimikashi ,Passive,,ManCharm,Moarimikashi@teleworm.us,,,,,,,,,,,,,,,,,,,,, -,,Dobromił Dąbrowski ,Passive,,Custom Lawn Care,DobromilDabrowski@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,Teigan Sinclair,Passive,,The Serendipity Dip,TeiganSinclair@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Fahad Guirguis,Passive,,Cavages,FahadSaidGuirguis@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Morten Olsen,Passive,,Gallenkamp,MortenJOlsen@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Christian Baecker,Passive,,Webcom Business Services,ChristianBaecker@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Sebastianus Dohmen,Passive,,Accord Investments,SebastianusDohmen@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Eero Koskinen,Passive,,American Appliance,EeroKoskinen@superrito.com,,,,,,,,,,,,,,,,,,,,, -,,富奎 盧,Passive,,Bettendorf's,LuFuKui@teleworm.us,,,,,,,,,,,,,,,,,,,,, -,,Milica Jelić,Passive,,House Of Denmark,MilicaJelic@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,Barbora Holubová,Passive,,10000 Auto Parts,BarboraHolubova@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Marta Kos,Passive,,Mages,MartaKos@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Simret Zula,Passive,,CSK Auto,SimretZula@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Kamil Chlubna,Passive,,Eagle Hardware & Garden,KamilChlubna@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Aceline Bolduc,Passive,,Rustler Steak House,AcelineBolduc@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Lucie Stupková,Passive,,ABCO Foods,LucieStupkova@gustr.com,,,,,,,,,,,,,,,,,,,,, -,,Roland Solvik,Passive,,Trak Auto,RolandSolvik@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Mekirinzukushitakufu ,Passive,,Choices,Mekirinzukushitakufu@teleworm.us,,,,,,,,,,,,,,,,,,,,, -,,Mukharbek Sultanovich,Passive,,Megatronic,MukharbekSultanovich@cuvox.de,,,,,,,,,,,,,,,,,,,,, -,,Osman Amanuel,Passive,,Handy Dan,OsmanAmanuel@dayrep.com,,,,,,,,,,,,,,,,,,,,, -,,幸子 阪部,Passive,,Channel Home Centers,dd@armyspy.com,,,,,,,,,,,,,,,,,,,,, -,,Masakazu Kamitani,Passive,,Honest Air Group,MasakazuKamitani@superrito.com,,,,,,,,,,,,,,,,,,,,, -,,Omran Sabbagh,Passive,,Pleasures and Pasttimes,OmranNuhaidSabbagh@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Rikako Matsumura,Passive,,Lazysize,RikakoMatsumura@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Anayolisa Chukwukadibia,Passive,,Prestiga-Biz,AnayolisaChukwukadibia@einrot.com,,,,,,,,,,,,,,,,,,,,, -,,Gudmunda Hinna,Passive,,Childs Restaurants,GudmundaHinna@armyspy.com,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file +,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,, +Notes:,,,,,,,,,,,,,,,,,,,,,,,,,, +Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,,,,,,, +First data column must be blank.,,,,,,,,,,,,,,,,,,,,,,,,,, +Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,,,,,,, +"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,,,,,,, +"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,,,,,,, +"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,,,,,, +You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,, +Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Next Contact By,Next Contact Date,Last Contact Date,Company,Unsubscribed,Blog Subscriber +Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,contact_by,contact_date,last_contact_date,company,unsubscribed,blog_subscriber +Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No +Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Date,Date,Link,Check,Check +Info:,,,"Lead, Open, Replied, Opportunity, Interested, Converted, Do Not Contact","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Profile,,,Valid Company,0 or 1,0 or 1 +Start entering data below this line,,,,,,,,,,,,,,,,,,,,,,,,,, +,,Mart Lakeman,Lead,,Zany Brainy,MartLakeman@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Saga Lundqvist,Lead,,Patterson-Fletcher,SagaLundqvist@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,Adna Sjöberg,Lead,,Griff's Hamburgers,AdnaSjoberg@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Ida Svendsen,Lead,,Rhodes Furniture,IdaDSvendsen@superrito.com,,,,,,,,,,,,,,,,,,,, +,,Emppu Hämeenniemi,Lead,,Burger Chef,EmppuHameenniemi@teleworm.us,,,,,,,,,,,,,,,,,,,, +,,Eugenio Pisano,Lead,,Stratabiz,EugenioPisano@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Semhar Hagos,Lead,,Home Quarters Warehouse,SemharHagos@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Branimira Ivanković,Lead,,Enviro Architectural Designs,BranimiraIvankovic@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Shelly Fields,Lead,,Ideal Garden Management,ShellyLFields@superrito.com,,,,,,,,,,,,,,,,,,,, +,,Leo Mikulić,Lead,,Listen Up,LeoMikulic@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Denisa Jarošová,Lead,,I. Magnin,DenisaJarosova@teleworm.us,,,,,,,,,,,,,,,,,,,, +,,Janek Rutkowski,Lead,,First Rate Choice,JanekRutkowski@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,美月 宇藤,Lead,,Multi Tech Development,mm@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Даниил Афанасьев,Lead,,National Auto Parts,dd@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Zorislav Petković,Lead,,Integra Investment Plan,ZorislavPetkovic@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Nanao Niwa,Lead,,The Lawn Guru,NanaoNiwa@superrito.com,,,,,,,,,,,,,,,,,,,, +,,Hreiðar Jörundsson,Lead,,Buena Vista Realty Service,HreiarJorundsson@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Lai Chu,Lead,,Bountiful Harvest Health Food Store,ChuThiBichLai@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Victor Aksakov,Lead,,P. Samuels Men's Clothiers,VictorAksakov@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,Saidalim Bisliev,Lead,,Vinyl Fever,SaidalimBisliev@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Totte Jakobsson,Lead,,Garden Master,TotteJakobsson@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Naná Armas,Lead,,Big Apple,NanaArmasRobles@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Walerian Duda,Lead,,Monk House Sales,WalerianDuda@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,Moarimikashi ,Lead,,ManCharm,Moarimikashi@teleworm.us,,,,,,,,,,,,,,,,,,,, +,,Dobromił Dąbrowski ,Lead,,Custom Lawn Care,DobromilDabrowski@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,Teigan Sinclair,Lead,,The Serendipity Dip,TeiganSinclair@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Fahad Guirguis,Lead,,Cavages,FahadSaidGuirguis@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Morten Olsen,Lead,,Gallenkamp,MortenJOlsen@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Christian Baecker,Lead,,Webcom Business Services,ChristianBaecker@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Sebastianus Dohmen,Lead,,Accord Investments,SebastianusDohmen@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Eero Koskinen,Lead,,American Appliance,EeroKoskinen@superrito.com,,,,,,,,,,,,,,,,,,,, +,,富奎 盧,Lead,,Bettendorf's,LuFuKui@teleworm.us,,,,,,,,,,,,,,,,,,,, +,,Milica Jelić,Lead,,House Of Denmark,MilicaJelic@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,Barbora Holubová,Lead,,10000 Auto Parts,BarboraHolubova@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Marta Kos,Lead,,Mages,MartaKos@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Simret Zula,Lead,,CSK Auto,SimretZula@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Kamil Chlubna,Lead,,Eagle Hardware & Garden,KamilChlubna@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Aceline Bolduc,Lead,,Rustler Steak House,AcelineBolduc@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Lucie Stupková,Lead,,ABCO Foods,LucieStupkova@gustr.com,,,,,,,,,,,,,,,,,,,, +,,Roland Solvik,Lead,,Trak Auto,RolandSolvik@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Mekirinzukushitakufu ,Lead,,Choices,Mekirinzukushitakufu@teleworm.us,,,,,,,,,,,,,,,,,,,, +,,Mukharbek Sultanovich,Lead,,Megatronic,MukharbekSultanovich@cuvox.de,,,,,,,,,,,,,,,,,,,, +,,Osman Amanuel,Lead,,Handy Dan,OsmanAmanuel@dayrep.com,,,,,,,,,,,,,,,,,,,, +,,幸子 阪部,Lead,,Channel Home Centers,dd@armyspy.com,,,,,,,,,,,,,,,,,,,, +,,Masakazu Kamitani,Lead,,Honest Air Group,MasakazuKamitani@superrito.com,,,,,,,,,,,,,,,,,,,, +,,Omran Sabbagh,Lead,,Pleasures and Pasttimes,OmranNuhaidSabbagh@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Rikako Matsumura,Lead,,Lazysize,RikakoMatsumura@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Anayolisa Chukwukadibia,Lead,,Prestiga-Biz,AnayolisaChukwukadibia@einrot.com,,,,,,,,,,,,,,,,,,,, +,,Gudmunda Hinna,Lead,,Childs Restaurants,GudmundaHinna@armyspy.com,,,,,,,,,,,,,,,,,,,, \ No newline at end of file From acc876e0d7b444a857b6618f8759394fb7d0e5b1 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 4 Oct 2013 13:33:24 +0530 Subject: [PATCH 060/123] [minor] [fix] status updater, only change communication status when called explicitly --- controllers/status_updater.py | 16 ++++++++++------ patches/october_2013/p03_crm_update_status.py | 18 +++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/controllers/status_updater.py b/controllers/status_updater.py index e457fa957e..b2a0e17a25 100644 --- a/controllers/status_updater.py +++ b/controllers/status_updater.py @@ -88,17 +88,21 @@ class StatusUpdater(DocListController): webnotes.conn.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status) def on_communication(self): + self.communication_set = True self.set_status(update=True) + del self.communication_set def communication_received(self): - last_comm = self.doclist.get({"doctype":"Communication"}) - if last_comm: - return last_comm[-1].sent_or_received == "Received" + if getattr(self, "communication_set", False): + last_comm = self.doclist.get({"doctype":"Communication"}) + if last_comm: + return last_comm[-1].sent_or_received == "Received" def communication_sent(self): - last_comm = self.doclist.get({"doctype":"Communication"}) - if last_comm: - return last_comm[-1].sent_or_received == "Sent" + if getattr(self, "communication_set", False): + last_comm = self.doclist.get({"doctype":"Communication"}) + if last_comm: + return last_comm[-1].sent_or_received == "Sent" def validate_qty(self): """ diff --git a/patches/october_2013/p03_crm_update_status.py b/patches/october_2013/p03_crm_update_status.py index 73ed1b1c78..07a70c642a 100644 --- a/patches/october_2013/p03_crm_update_status.py +++ b/patches/october_2013/p03_crm_update_status.py @@ -36,12 +36,12 @@ def execute(): webnotes.conn.sql("""update `tab%s` set status=%s where status=%s""" % \ (dt, "%s", "%s"), (status[1], status[0])) - # for dt in ["Lead", "Opportunity"]: - # for name in webnotes.conn.sql_list("""select name from `tab%s`""" % dt): - # bean = webnotes.bean(dt, name) - # before_status = bean.doc.status - # bean.get_controller().set_status() - # - # if bean.doc.status != before_status: - # webnotes.conn.sql("""update `tab%s` set status=%s where name=%s""" % (dt, "%s", "%s"), - # (bean.doc.status, name)) + for dt in ["Lead", "Opportunity"]: + for name in webnotes.conn.sql_list("""select name from `tab%s`""" % dt): + bean = webnotes.bean(dt, name) + before_status = bean.doc.status + bean.get_controller().set_status() + + if bean.doc.status != before_status: + webnotes.conn.sql("""update `tab%s` set status=%s where name=%s""" % (dt, "%s", "%s"), + (bean.doc.status, name)) From b646b3b3e661c55308aa43bd082fa3eebb6be8e2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 14:30:33 +0530 Subject: [PATCH 061/123] [patch] [minor] perpetual inventory stock transfer utility --- ...petual_inventory_stock_transfer_utility.py | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index f59ebdb55b..2b39be69a5 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import nowdate, nowtime +from webnotes.utils import nowdate, nowtime, cstr from accounts.utils import get_fiscal_year def execute(): @@ -12,7 +12,8 @@ def execute(): item_map.setdefault(item.name, item) warehouse_map = get_warehosue_map() - # naming_series = + naming_series = "STE/13/" + for company in webnotes.conn.sql("select name from tabCompany"): stock_entry = [{ "doctype": "Stock Entry", @@ -22,16 +23,28 @@ def execute(): "purpose": "Material Transfer", "company": company[0], "remarks": "Material Transfer to activate perpetual inventory", - "fiscal_year": get_fiscal_year(nowdate()) + "fiscal_year": get_fiscal_year(nowdate())[0] }] expense_account = "Cost of Goods Sold - NISL" cost_center = "Default CC Ledger - NISL" - for bin in webnotes.conn.sql("select * from tabBin where company=%s", company[0] as_dict=1): - new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ - if cstr(item_map[bin.item_code]) == "Yes" else wh.get("current_asset_warehouse") - + for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!='' + and ifnull(warehouse, '')!='' and ifnull(actual_qty, 0) != 0 + and (select company from tabWarehouse where name=bin.warehouse)=%s""", + company[0], as_dict=1): item_details = item_map[bin.item_code] + new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ + if cstr(item_details.is_asset_item) == "Yes" \ + else warehouse_map[bin.warehouse].get("current_asset_warehouse") + + if item_details.has_serial_no == "Yes": + serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name + from `tabSerial No` where item_code = %s and warehouse = %s""", + (bin.item_code, bin.warehouse))]) + print serial_no + else: + serial_no = None + stock_entry.append({ "doctype": "Stock Entry Detail", "parentfield": "mtn_details", @@ -45,9 +58,10 @@ def execute(): "stock_uom": item_details.stock_uom, "conversion_factor": 1, "expense_account": expense_account, - "cost_center": cost_center + "cost_center": cost_center, + "serial_no": serial_no }) - + webnotes.bean(stock_entry).insert() def get_warehosue_map(): @@ -64,7 +78,7 @@ def get_warehosue_map(): "current_asset_warehouse": "Transit-New - NISL", "fixed_asset_warehouse": "" }, - "ASSET-MAHAPE": { + "ASSET - MAHAPE": { "current_asset_warehouse": "", "fixed_asset_warehouse": "Assets-New - NISL" } From 27c9ecc5384394d4ca6080ebf51ea2784078aae9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 14:41:41 +0530 Subject: [PATCH 062/123] [patch] [minor] perpetual inventory stock transfer utility --- .../october_2013/perpetual_inventory_stock_transfer_utility.py | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index 2b39be69a5..c02656285f 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -41,7 +41,6 @@ def execute(): serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name from `tabSerial No` where item_code = %s and warehouse = %s""", (bin.item_code, bin.warehouse))]) - print serial_no else: serial_no = None From 5f8477d4ef7af34d2a6bf54afeb13251ed92dc54 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 15:29:36 +0530 Subject: [PATCH 063/123] [patch] [minor] perpetual inventory stock transfer utility --- .../perpetual_inventory_stock_transfer_utility.py | 4 ++-- stock/doctype/stock_entry/stock_entry.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index c02656285f..8cee29a824 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -39,8 +39,8 @@ def execute(): if item_details.has_serial_no == "Yes": serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name - from `tabSerial No` where item_code = %s and warehouse = %s""", - (bin.item_code, bin.warehouse))]) + from `tabSerial No` where item_code = %s and warehouse = %s + and status='Available'""", (bin.item_code, bin.warehouse))]) else: serial_no = None diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index a54f9bf05b..8c4b97e091 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -42,7 +42,7 @@ class DocType(StockController): self.validate_warehouse(pro_obj) self.validate_production_order(pro_obj) self.get_stock_and_rate() - self.validate_incoming_rate() + # self.validate_incoming_rate() self.validate_bom() self.validate_finished_goods() self.validate_return_reference_doc() From ac90ecf946773bc5fab70a04cd7ed9812e3d1b76 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 4 Oct 2013 15:36:29 +0530 Subject: [PATCH 064/123] [patch] [minor] perpetual inventory stock transfer utility --- stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 8c4b97e091..a54f9bf05b 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -42,7 +42,7 @@ class DocType(StockController): self.validate_warehouse(pro_obj) self.validate_production_order(pro_obj) self.get_stock_and_rate() - # self.validate_incoming_rate() + self.validate_incoming_rate() self.validate_bom() self.validate_finished_goods() self.validate_return_reference_doc() From ecb83e8762bc56bc1f8423dc4b76d1ead4f5c793 Mon Sep 17 00:00:00 2001 From: Priya Date: Fri, 4 Oct 2013 17:18:00 +0530 Subject: [PATCH 065/123] [docs] 5day setup-page 3 added --- docs/user/docs.user.md | 1 + .../five_step_setup/docs.user.five.day_3.md | 135 ++++++++++++++++++ docs/user/five_step_setup/docs.user.five.md | 6 +- .../intro/docs.user.implement.strategy.md | 2 +- 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_3.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 82e211f1ce..098fd89e27 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -33,6 +33,7 @@ Contents 1. [Five-Day-Setup](docs.user.five.html) 1. [Day-1](docs.user.five.day_1.html) 1. [Day-2](docs.user.five.day_2.html) + 1. [Day-3](docs.user.five.day_3.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_3.md b/docs/user/five_step_setup/docs.user.five.day_3.md new file mode 100644 index 0000000000..09a5d3f4ac --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_3.md @@ -0,0 +1,135 @@ +--- +{ + "_label": "Day-3" +} +--- +After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. + + +### Sales Cycle + +Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) + +#### Lead + +To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. + +![Lead](img/thirddaysetup_lead.png) + +Fill the Lead form. + +> To understand Lead in detail, visit [Lead](docs.user.selling.lead.html) + +#### Opportunity + +After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page. + +##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status. + +![Opportunity](img/thirddaysetup_opportunity_1.png) + +
+ +##### Step 2: Generate Opportunity from the selected Lead + +![Opportunity](img/thirddaysetup_opportunity.png) + +You can also generate an Opportunity directly from the Selling Page. + +> To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html). + + +#### Quotation + +Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. + +![Quotation](img/thirddaysetup_quotation.png) + +You can also generate a Quotation directly from the Selling Page. + +> To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html) + + +#### Sales Order + +Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. + +![Sales Order](img/thirddaysetup_sales_order.png) + +You can also generate a Sales Order directly from the Selling Page. + +> To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html). + +#### Delivery Note + +If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. + + +![Delivery Note](img/thirddaysetup_delivery_note.png) + +> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) + + +#### Sales Invoice + +Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. + +![Sales Invoice](img/thirddaysetup_sales_invoice.png) + +
+ +#### Payment (Journal Voucher) + + +A Journal Voucher or a payment entry can be generated directly from the Sales Invoice. + +![Payment Entry](img/thirddaysetup_payment_entry.png) + +> To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) + +
+ +### Purchase Cycle + +Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). + + +#### Material Request + +To create a Material Request, go to Stock/Buying and Click on Material Request. + +![Material Request](img/thirddaysetup-material-request.png) + +> To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html) + +#### Purchase Order + +To create a Purchase Order go to Buying and click on Purchase Order + +![Purchase Order](img/thirddaysetup-purchase-order.png) + +> To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html) + +#### Purchase Receipt + +To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt. + +![Purchase Receipt](img/thirddaysetup-purchase-receipt.png) + +
+ +>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html) + +
+ +#### Payment( Journal Voucher) + +Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices. + + +![Payment Entry](img/thirddaysetup-payment-entry.png) + +
+ +> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). + diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md index 4203fad62a..14b761b31e 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_step_setup/docs.user.five.md @@ -3,7 +3,8 @@ "_label": "Five-Day Setup", "_toc": [ "docs.user.five.day_1", - "docs.user.five.day_2" + "docs.user.five.day_2", + "docs.user.five.day_3" ] } @@ -30,11 +31,12 @@ The setup help is divided into day-wise instructions for 5 consecutive days. Day - Sales Cycle - Purchase Cycle -- Manufacturing Cycle + #### Day 4 +- Manufacturing Cycle - Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc - Accounts diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 9ec58e8874..8f05af7f53 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -13,7 +13,7 @@ Before you start managing your Operations in EPRNext, you must first become fami - Create your first Customer, Supplier and Item. Add a few more so you get familiar with them. - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) -- Complete a standard purchase cycle - Purchase Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). +- Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). - Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush) > Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive. From ae307e8bf835d0587877b7cd3818be20596288e7 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 4 Oct 2013 17:48:05 +0530 Subject: [PATCH 066/123] [setup wizard] Started - WIP --- setup/page/setup_wizard/__init__.py | 0 setup/page/setup_wizard/setup_wizard.js | 217 +++++++++++++++++++++++ setup/page/setup_wizard/setup_wizard.txt | 32 ++++ 3 files changed, 249 insertions(+) create mode 100644 setup/page/setup_wizard/__init__.py create mode 100644 setup/page/setup_wizard/setup_wizard.js create mode 100644 setup/page/setup_wizard/setup_wizard.txt diff --git a/setup/page/setup_wizard/__init__.py b/setup/page/setup_wizard/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js new file mode 100644 index 0000000000..b88f6e6c13 --- /dev/null +++ b/setup/page/setup_wizard/setup_wizard.js @@ -0,0 +1,217 @@ +wn.pages['setup-wizard'].onload = function(wrapper) { + erpnext.wiz = new wn.wiz.Wizard({ + parent: wrapper, + title: wn._("ERPNext Setup Guide"), + slides: [ + // User + { + title: wn._("The First User"), + fields: [ + {"fieldname": "first_name", "label": wn._("First Name"), "fieldtype": "Data", reqd:1}, + {"fieldname": "last_name", "label": wn._("Last Name"), "fieldtype": "Data", reqd:1}, + ], + help: wn._('The first user will become the System Manager (you can change that later).') + }, + + // Organization + { + title: wn._("The Organization"), + fields: [ + {fieldname:'company_name', label: wn._('Company Name'), fieldtype:'Data', reqd:1, + placeholder: 'e.g. "My Company LLC"'}, + {fieldname:'company_abbr', label: wn._('Company Abbreviation'), fieldtype:'Data', + placeholder:'e.g. "MC"',reqd:1}, + {fieldname:'company_tagline', label: wn._('What does it do?'), fieldtype:'Data', + placeholder:'e.g. "Build tools for builders"',reqd:1}, + ], + help: wn._('The name of your company for which you are setting up this system.'), + onload: function(slide) { + slide.get_input("company_name").on("change", function() { + var parts = slide.get_input("company_name").val().split(" "); + var abbr = $.map(parts, function(p) { return p ? p.substr(0,1) : null }).join(""); + slide.get_input("company_abbr").val(abbr.toUpperCase()); + }); + } + }, + + // Country + { + title: wn._("Country, Timezone and Currency"), + fields: [ + {fieldname:'country', label: wn._('Country'), reqd:1, + options: "", fieldtype: 'Select'}, + {fieldname:'currency', label: wn._('Default Currency'), reqd:1, + options: "", fieldtype: 'Select'}, + {fieldname:'timezone', label: wn._('Time Zone'), reqd:1, + options: "", fieldtype: 'Select'}, + ], + help: wn._('Select your home country and check the timezone and currency.'), + onload: function(slide, form) { + wn.call({ + method:"webnotes.country_info.get_country_timezone_info", + callback: function(data) { + erpnext.country_info = data.message.country_info; + erpnext.all_timezones = data.message.all_timezones; + slide.get_input("country").empty() + .add_options([""].concat(keys(erpnext.country_info).sort())); + slide.get_input("currency").empty() + .add_options(wn.utils.unique([""].concat($.map(erpnext.country_info, + function(opts, country) { return opts.currency; }))).sort()); + slide.get_input("timezone").empty() + .add_options([""].concat(erpnext.all_timezones)); + } + }) + + slide.get_input("country").on("change", function() { + var country = slide.get_input("country").val(); + var $timezone = slide.get_input("timezone"); + $timezone.empty(); + // add country specific timezones first + if(country){ + var timezone_list = erpnext.country_info[country].timezones || []; + $timezone.add_options(timezone_list.sort()); + slide.get_input("currency").val(erpnext.country_info[country].currency); + } + // add all timezones at the end, so that user has the option to change it to any timezone + $timezone.add_options([""].concat(erpnext.all_timezones)); + + }); + } + }, + + // Logo + { + title: wn._("Logo and Letter Heads"), + help: wn._('Upload your letter head and logo - you can edit them later.'), + html: '

' + wn._('Upload Logo') + '


' + +'

' + wn._('Upload Letter Head') + '

', + onload: function(slide) { + wn.upload.make({ + parent: slide.$wrapper.find(".upload-area-letter-head").css({"margin-left": "10px"}), + on_attach: function(fileobj) { + console.log(fileobj); + } + }); + + wn.upload.make({ + parent: slide.$wrapper.find(".upload-area-logo").css({"margin-left": "10px"}), + on_attach: function(fileobj) { + console.log(fileobj); + } + }); + } + + }, + + // Taxes + { + "title": wn._("Add Taxes"), + "help": wn._("List your tax heads (e.g. VAT, Excise) (upto 3) and their standard rates. This will create a standard template, you can edit and add more later."), + "fields": [ + {fieldtype:"Data", fieldname:"tax_1", label:"Tax 1", placeholder:"e.g. VAT"}, + {fieldtype:"Data", fieldname:"tax_rate_1", label:"Rate for Tax 1 (%)", placeholder:"e.g. 5"}, + {fieldtype:"Data", fieldname:"tax_2", label:"Tax 2", placeholder:"e.g. Customs Duty"}, + {fieldtype:"Data", fieldname:"tax_rate_2", label:"Rate for Tax 2 (%)", placeholder:"e.g. 5"}, + {fieldtype:"Data", fieldname:"tax_3", label:"Tax 3", placeholder:"e.g. Excise"}, + {fieldtype:"Data", fieldname:"tax_rate_3", label:"Rate for Tax 3 (%)", placeholder:"e.g. 5"}, + ], + onload: function(slide) { + slide.form.fields_dict.tax_rate_1.$wrapper.css("margin-left", "50%"); + slide.form.fields_dict.tax_rate_2.$wrapper.css("margin-left", "50%"); + slide.form.fields_dict.tax_rate_3.$wrapper.css("margin-left", "50%"); + } + } + + // + ] + + }) +} + +wn.pages['setup-wizard'].onshow = function(wrapper) { + erpnext.wiz.show(wn.get_route()[1] || "0"); +} + +wn.provide("wn.wiz"); + +wn.wiz.Wizard = Class.extend({ + init: function(opts) { + $.extend(this, opts); + this.slide_dict = {}; + wn.set_route("setup-wizard", "0"); + }, + show: function(id) { + id = cint(id); + if(this.current_slide && this.current_slide.id===id) + return; + if(!this.slide_dict[id]) { + this.slide_dict[id] = new wn.wiz.WizardSlide($.extend(this.slides[id], {wiz:this, id:id})); + this.slide_dict[id].make(); + } + + if(this.current_slide) + this.current_slide.$wrapper.toggle(false); + + this.current_slide = this.slide_dict[id]; + this.current_slide.$wrapper.toggle(true); + }, +}); + +wn.wiz.WizardSlide = Class.extend({ + init: function(opts) { + $.extend(this, opts); + }, + make: function() { + var me = this; + this.$wrapper = $(repl('
\ +
%(main_title)s: %(title)s
\ +
\ +
\ +
\ +
\ +
\ +
\ +

%(title)s

%(help)s

\ +
\ +
\ + \ +
\ +
', {help:this.help, title:this.title, main_title:this.wiz.title, width: (flt(this.id + 1) / this.wiz.slides.length) * 100})) + .appendTo(this.wiz.parent); + + this.body = this.$wrapper.find(".form")[0]; + + if(this.fields) { + this.form = new wn.ui.FieldGroup({ + fields: this.fields, + body: this.body + }); + this.form.make(); + } else { + $(this.body).html(this.html) + } + + if(this.id > 0) { + this.$prev = $("") + .click(function() { wn.set_route("setup-wizard", me.id-1 + ""); }) + .appendTo(this.$wrapper.find(".footer")) + .css({"margin-right": "5px"}); + } + if(this.id+1 < this.wiz.slides.length) { + this.$next = $("") + .click(function() { wn.set_route("setup-wizard", me.id+1 + ""); }) + .appendTo(this.$wrapper.find(".footer")); + } else { + this.$complete = $("") + .click(function() { me.wiz.complete(); }).appendTo(this.$wrapper.find(".footer")); + } + + if(this.onload) { + this.onload(this); + } + + }, + get_input: function(fn) { + return this.form.get_input(fn); + } +}) \ No newline at end of file diff --git a/setup/page/setup_wizard/setup_wizard.txt b/setup/page/setup_wizard/setup_wizard.txt new file mode 100644 index 0000000000..996fd1a059 --- /dev/null +++ b/setup/page/setup_wizard/setup_wizard.txt @@ -0,0 +1,32 @@ +[ + { + "creation": "2013-10-04 13:49:33", + "docstatus": 0, + "modified": "2013-10-04 13:49:33", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Page", + "module": "Setup", + "name": "__common__", + "page_name": "setup-wizard", + "standard": "Yes", + "title": "Setup Wizard" + }, + { + "doctype": "Page Role", + "name": "__common__", + "parent": "setup-wizard", + "parentfield": "roles", + "parenttype": "Page", + "role": "System Manager" + }, + { + "doctype": "Page", + "name": "setup-wizard" + }, + { + "doctype": "Page Role" + } +] \ No newline at end of file From 3df4f8898b82158537c2f182c36c3abdf2abc0e0 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 4 Oct 2013 21:19:30 +0530 Subject: [PATCH 067/123] [minor] crm funnel first cut --- selling/page/crm_funnel/__init__.py | 0 selling/page/crm_funnel/crm_funnel.css | 3 + selling/page/crm_funnel/crm_funnel.js | 176 +++++++++++++++++++++++++ selling/page/crm_funnel/crm_funnel.py | 33 +++++ selling/page/crm_funnel/crm_funnel.txt | 33 +++++ 5 files changed, 245 insertions(+) create mode 100644 selling/page/crm_funnel/__init__.py create mode 100644 selling/page/crm_funnel/crm_funnel.css create mode 100644 selling/page/crm_funnel/crm_funnel.js create mode 100644 selling/page/crm_funnel/crm_funnel.py create mode 100644 selling/page/crm_funnel/crm_funnel.txt diff --git a/selling/page/crm_funnel/__init__.py b/selling/page/crm_funnel/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/selling/page/crm_funnel/crm_funnel.css b/selling/page/crm_funnel/crm_funnel.css new file mode 100644 index 0000000000..89e904fcfc --- /dev/null +++ b/selling/page/crm_funnel/crm_funnel.css @@ -0,0 +1,3 @@ +.funnel-wrapper { + margin: 15px; +} \ No newline at end of file diff --git a/selling/page/crm_funnel/crm_funnel.js b/selling/page/crm_funnel/crm_funnel.js new file mode 100644 index 0000000000..a2d2b93479 --- /dev/null +++ b/selling/page/crm_funnel/crm_funnel.js @@ -0,0 +1,176 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +// License: GNU General Public License v3. See license.txt + +wn.pages['crm-funnel'].onload = function(wrapper) { + wn.ui.make_app_page({ + parent: wrapper, + title: 'CRM Funnel', + single_column: true + }); + + wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper); +} + +erpnext.CRMFunnel = Class.extend({ + init: function(wrapper) { + var me = this; + // 0 setTimeout hack - this gives time for canvas to get width and height + setTimeout(function() { + me.setup(wrapper); + me.get_data(); + }, 0); + }, + + setup: function(wrapper) { + var me = this; + + this.elements = { + layout: $(wrapper).find(".layout-main"), + from_date: wrapper.appframe.add_date("From Date"), + to_date: wrapper.appframe.add_date("To Date"), + refresh_btn: wrapper.appframe.add_button("Refresh", + function() { me.get_data(); }, "icon-refresh"), + }; + + this.elements.no_data = $('
No Data
') + .toggle(false) + .appendTo(this.elements.layout); + + this.elements.funnel_wrapper = $('
') + .appendTo(this.elements.layout); + + this.options = { + from_date: wn.datetime.get_today(), + to_date: wn.datetime.add_months(wn.datetime.get_today(), -1) + }; + + // set defaults and bind on change + $.each(this.options, function(k, v) { + me.elements[k].val(wn.datetime.str_to_user(v)); + me.elements[k].on("change", function() { + me.options[k] = wn.datetime.user_to_str($(this).val()); + me.get_data(); + }); + }); + + // bind refresh + this.elements.refresh_btn.on("click", function() { + me.get_data(this); + }); + + // bind resize + $(window).resize(function() { + me.render(); + }); + }, + + get_data: function(btn) { + var me = this; + wn.call({ + module: "selling", + page: "crm_funnel", + method: "get_funnel_data", + args: { + from_date: this.options.from_date, + to_date: this.options.to_date + }, + btn: btn, + callback: function(r) { + if(!r.exc) { + me.options.data = r.message; + me.render(); + } + } + }); + }, + + render: function() { + var me = this; + this.prepare(); + + var context = this.elements.context, + x_start = 0.0, + x_end = this.options.width, + x_mid = (x_end - x_start) / 2.0, + y = 0, + y_old = 0.0; + + if(this.options.total_value === 0) { + this.elements.no_data.toggle(true); + return; + } + + this.options.data.forEach(function(d) { + context.fillStyle = d.color; + context.strokeStyle = d.color; + me.draw_triangle(x_start, x_mid, x_end, y, me.options.height); + + y_old = y; + + // new y + y = y + (me.options.height * d.value / me.options.total_value); + + // new x + var half_side = (me.options.height - y) / Math.sqrt(3); + x_start = x_mid - half_side; + x_end = x_mid + half_side; + + var y_mid = y_old + (y - y_old) / 2.0; + + me.draw_legend(x_mid, y_mid, me.options.width, me.options.height, d.value + " - " + d.title); + }); + }, + + prepare: function() { + this.elements.no_data.toggle(false); + + // calculate width and height options + this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0; + this.options.height = (Math.sqrt(3) * this.options.width) / 2.0; + + // calculate total value + this.options.total_value = this.options.data.reduce( + function(prev, curr) { return prev + curr.value; }, 0.0); + + this.elements.canvas = $('') + .appendTo(this.elements.funnel_wrapper.empty()) + .attr("width", $(this.elements.funnel_wrapper).width()) + .attr("height", this.options.height); + + this.elements.context = this.elements.canvas.get(0).getContext("2d"); + }, + + draw_triangle: function(x_start, x_mid, x_end, y, height) { + var context = this.elements.context; + context.beginPath(); + context.moveTo(x_start, y); + context.lineTo(x_end, y); + context.lineTo(x_mid, height); + context.lineTo(x_start, y); + context.closePath(); + context.fill(); + }, + + draw_legend: function(x_mid, y_mid, width, height, title) { + var context = this.elements.context; + + // draw line + context.beginPath(); + context.moveTo(x_mid, y_mid); + context.lineTo(width, y_mid); + context.closePath(); + context.stroke(); + + // draw circle + context.beginPath(); + context.arc(width, y_mid, 5, 0, Math.PI * 2, false); + context.closePath(); + context.fill(); + + // draw text + context.fillStyle = "black"; + context.textBaseline = "middle"; + context.font = "1.1em sans-serif"; + context.fillText(title, width + 20, y_mid); + } +}); \ No newline at end of file diff --git a/selling/page/crm_funnel/crm_funnel.py b/selling/page/crm_funnel/crm_funnel.py new file mode 100644 index 0000000000..be0aebe7bb --- /dev/null +++ b/selling/page/crm_funnel/crm_funnel.py @@ -0,0 +1,33 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +@webnotes.whitelist() +def get_funnel_data(from_date, to_date): + active_leads = webnotes.conn.sql("""select count(*) from `tabLead` + where (`modified` between %s and %s) + and status != "Do Not Contact" """, (from_date, to_date))[0][0] + + active_leads += webnotes.conn.sql("""select count(distinct customer) from `tabContact` + where (`modified` between %s and %s) + and status != "Passive" """, (from_date, to_date))[0][0] + + opportunities = webnotes.conn.sql("""select count(*) from `tabOpportunity` + where docstatus = 1 and (`modified` between %s and %s) + and status != "Lost" """, (from_date, to_date))[0][0] + + quotations = webnotes.conn.sql("""select count(*) from `tabQuotation` + where docstatus = 1 and (`modified` between %s and %s) + and status != "Lost" """, (from_date, to_date))[0][0] + + sales_orders = webnotes.conn.sql("""select count(*) from `tabQuotation` + where docstatus = 1 and (`modified` between %s and %s)""", (from_date, to_date))[0][0] + + return [ + { "title": "Active Leads / Customers", "value": active_leads, "color": "#B03B46" }, + { "title": "Opportunities", "value": opportunities, "color": "#F09C00" }, + { "title": "Quotations", "value": quotations, "color": "#006685" }, + { "title": "Sales Orders", "value": sales_orders, "color": "#00AD65" } + ] diff --git a/selling/page/crm_funnel/crm_funnel.txt b/selling/page/crm_funnel/crm_funnel.txt new file mode 100644 index 0000000000..29cf566053 --- /dev/null +++ b/selling/page/crm_funnel/crm_funnel.txt @@ -0,0 +1,33 @@ +[ + { + "creation": "2013-10-04 13:17:18", + "docstatus": 0, + "modified": "2013-10-04 13:17:18", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Page", + "icon": "icon-filter", + "module": "Selling", + "name": "__common__", + "page_name": "crm-funnel", + "standard": "Yes", + "title": "CRM Funnel" + }, + { + "doctype": "Page Role", + "name": "__common__", + "parent": "crm-funnel", + "parentfield": "roles", + "parenttype": "Page", + "role": "Sales Manager" + }, + { + "doctype": "Page", + "name": "crm-funnel" + }, + { + "doctype": "Page Role" + } +] \ No newline at end of file From fb0274b2495b26e8a18e65e64705a05c8e939065 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 14:56:53 +0530 Subject: [PATCH 068/123] [patch] [minor] fix serial no status --- .../october_2013/p01_fix_serial_no_status.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 patches/october_2013/p01_fix_serial_no_status.py diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py new file mode 100644 index 0000000000..8700290fcd --- /dev/null +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -0,0 +1,40 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(): + serial_nos = webnotes.conn.sql("""select name, item_code, status from `tabSerial No` + where status!='Not in Use'""", as_dict=1) + for sr in serial_nos: + last_sle = webnotes.conn.sql("""select voucher_type, voucher_no, actual_qty + from `tabStock Ledger Entry` where serial_no like %s and item_code=%s + order by name desc limit 1""", + ("%%%s%%" % sr.name, sr.item_code), as_dict=1) + + if flt(last_sle[0].actual_qty) > 0: + if last_sle[0].voucher_type == "Stock Entry" and webnotes.conn.get_value("Stock Entry", + last_sle[0].voucher_no, "purpose") == "Sales Return": + status = "Sales Returned" + else: + status = "Available" + else: + if last_sle[0].voucher_type == "Stock Entry": + purpose = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, "purpose") + if purpose == "Purchase Return": + status = "Purchase Returned" + else: + status = "Not Available" + else: + status = "Delivered" + if sr.status != status: + webnotes.conn.sql("""update `tabSerial No` set status=%s where name=%s""", + (status, sr.name)) + + webnotes.conn.sql("""update `tabSerial No` set warehouse='' + where status in ('Delivered', 'Purchase Returned')""") + + + \ No newline at end of file From 0352f9b8270de20684bb70700f85d40e4289a056 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 15:38:43 +0530 Subject: [PATCH 069/123] [fix] [minor] gl entry cancellation --- accounts/doctype/gl_entry/gl_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index db6de44f09..0c11198be9 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -107,7 +107,7 @@ class DocType: _(" does not belong to the company") + ": " + self.doc.company) def check_negative_balance(account, adv_adj=False): - if not adv_adj: + if not adv_adj and account: account_details = webnotes.conn.get_value("Account", account, ["allow_negative_balance", "debit_or_credit"], as_dict=True) if not account_details["allow_negative_balance"]: From 704a915feb29e80377d0adbbb617ca9746bff031 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 17:20:23 +0530 Subject: [PATCH 070/123] [fix] [minor] [delivery note] --- selling/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 801d82bf40..6e74ac4869 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -74,7 +74,7 @@ def get_item_details(args): out.update(apply_pos_settings(pos_settings, out)) if args.doctype in ("Sales Invoice", "Delivery Note"): - if item_bean.doc.has_serial_no and not args.serial_no: + if item_bean.doc.has_serial_no == "Yes" and not args.serial_no: out.serial_no = _get_serial_nos_by_fifo(args, item_bean) return out From 842e9d60cc8118bef78c4e57a6040f69c149989f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 5 Oct 2013 19:57:39 +0530 Subject: [PATCH 071/123] [fix] [minor] serial no update --- stock/doctype/stock_ledger_entry/stock_ledger_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 1c3d3e132d..c29ca3a173 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -166,7 +166,7 @@ class DocType(DocListController): serial_nos.append(self.make_serial_no(make_autoname(item_det.serial_no_series))) self.doc.serial_no = "\n".join(serial_nos) else: - webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item), + webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item_code), SerialNoRequiredError) def make_serial_no(self, serial_no): From e342a75ff96a55a3bccf273efb4d6c99a2e35615 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 7 Oct 2013 12:16:28 +0530 Subject: [PATCH 072/123] [docs] five day setup complete --- docs/user/docs.user.md | 2 + .../five_step_setup/docs.user.five.day_4.md | 96 +++++++++++++++++++ .../five_step_setup/docs.user.five.day_5.md | 34 +++++++ docs/user/five_step_setup/docs.user.five.md | 13 +-- .../intro/docs.user.implement.strategy.md | 2 +- 5 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 docs/user/five_step_setup/docs.user.five.day_4.md create mode 100644 docs/user/five_step_setup/docs.user.five.day_5.md diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 098fd89e27..3aa3c9e414 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -34,6 +34,8 @@ Contents 1. [Day-1](docs.user.five.day_1.html) 1. [Day-2](docs.user.five.day_2.html) 1. [Day-3](docs.user.five.day_3.html) + 1. [Day-4](docs.user.five.day_4.html) + 1. [Day-5](docs.user.five.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_4.md b/docs/user/five_step_setup/docs.user.five.day_4.md new file mode 100644 index 0000000000..d23fe54585 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_4.md @@ -0,0 +1,96 @@ +--- +{ + "_label": "Day-4" +} +--- + +### Manufacturing Cycle + +Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (material issue) > Stock Entry (sales return) + +#### Bill of Materials + +To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. + +![Bill of Materials](img/fourthdaysetup_bom.png) + +
+ +> To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html) + +#### Production Planning Tool + +To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. + +![Production Planning Page](img/fourthdaysetup_ppt.png) + +
+ +> To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html) + + +#### Production Order + +To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. + +![Production Order](img/fourthdaysetup_po.png) + +
+ +> To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html) + +#### Stock Entry + +To go to Stock Entry, click on the Stock Icon and go to Stock Entry. + +![Stock Entry](img/fourthdaysetup_stock.png) + +
+ +> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html) + + +> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html) + + +#### Delivery Note + +To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. + +[Delivery Note](img/fourthdaysetup_delivery_note.png) + +
+ +> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) + + + +#### Warehouse + +To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. + +![Warehouse](img/fourthdaysetup_warehouse.png) + +
+ +> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) + + +#### Accounts + +Make a few Journal Vouchers. Generate some Accounting Reports. + +#### Journal Voucher. + +To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. + +![Journal Voucher](img/fourthdaysetup_jv.png) + +> To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) + +#### Accounting Reports + +Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register. + +> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) + diff --git a/docs/user/five_step_setup/docs.user.five.day_5.md b/docs/user/five_step_setup/docs.user.five.day_5.md new file mode 100644 index 0000000000..30c64c3708 --- /dev/null +++ b/docs/user/five_step_setup/docs.user.five.day_5.md @@ -0,0 +1,34 @@ +--- +{ + "_label": "Day-5" +} +--- + +#### Projects + +ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people. + +#### Tasks + +Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project. + +To create a Task, go to Project and click on Task. + +![Tasks](img/fifthdaysetup_task.png) + +
+ + +> To understand Projects in detail, visit [Projects](docs.user.projects.html) + +> To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html) + +#### Calendar + +> To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html) + + +#### Website + +> To understand Website in detail, visit [Website](docs.user.website.html) + diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_step_setup/docs.user.five.md index 14b761b31e..21170c5988 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_step_setup/docs.user.five.md @@ -4,7 +4,9 @@ "_toc": [ "docs.user.five.day_1", "docs.user.five.day_2", - "docs.user.five.day_3" + "docs.user.five.day_3", + "docs.user.five.day_4", + "docs.user.five.day_5" ] } @@ -33,16 +35,15 @@ The setup help is divided into day-wise instructions for 5 consecutive days. Day - Purchase Cycle - #### Day 4 - Manufacturing Cycle -- Fulfillment Cycle- Inventory, Delivery Note, Warehouse etc +- Delivery Note and Warehouse - Accounts #### Day 5 -- Billing -- Payments -- HR Reports +- Projects +- Calendar +- Website diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 8f05af7f53..735fe1e525 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -14,7 +14,7 @@ Before you start managing your Operations in EPRNext, you must first become fami - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) - Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). -- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush) +- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Material Issue > Sales Return > Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive. From 8f05c05bfb96b0a03f1ddbe2ae4e3fdfa951461d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 7 Oct 2013 13:08:13 +0530 Subject: [PATCH 073/123] Validate warehouse for allowed users and matched company --- controllers/buying_controller.py | 19 +++++++----- .../production_order/production_order.py | 29 +++++++++++-------- selling/doctype/sales_order/sales_order.py | 7 +++-- .../material_request/material_request.py | 12 ++------ .../stock_ledger_entry/stock_ledger_entry.py | 12 ++------ stock/utils.py | 7 +++++ 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 7e49e60f8a..25d76aa66d 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -24,7 +24,7 @@ class BuyingController(StockController): self.doc.supplier_name = webnotes.conn.get_value("Supplier", self.doc.supplier, "supplier_name") self.validate_stock_or_nonstock_items() - self.validate_warehouse_belongs_to_company() + self.validate_warehouse() def set_missing_values(self, for_validate=False): super(BuyingController, self).set_missing_values(for_validate) @@ -49,17 +49,20 @@ class BuyingController(StockController): if supplier: self.doc.supplier = supplier break + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + warehouses = list(set([d.warehouse for d in + self.doclist.get({"doctype": self.tname}) if d.warehouse])) + + for w in warehouses: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def get_purchase_tax_details(self): self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details") self.set_taxes("purchase_tax_details", "purchase_other_charges") - - def validate_warehouse_belongs_to_company(self): - for warehouse, company in webnotes.conn.get_values("Warehouse", - self.doclist.get_distinct_values("warehouse"), "company").items(): - if company and company != self.doc.company: - webnotes.msgprint(_("Company mismatch for Warehouse") + (": %s" % (warehouse,)), - raise_exception=WrongWarehouseCompany) def validate_stock_or_nonstock_items(self): if not self.get_stock_items(): diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 6447c0aa12..719d149e64 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -22,13 +22,14 @@ class DocType: utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "In Process", "Completed", "Cancelled"]) - if self.doc.production_item : - item_detail = sql("select name from `tabItem` where name = '%s' and docstatus != 2" - % self.doc.production_item, as_dict = 1) - if not item_detail: - msgprint("Item '%s' does not exist or cancelled in the system." - % cstr(self.doc.production_item), raise_exception=1) - + self.validate_bom_no() + self.validate_sales_order() + self.validate_warehouse() + + from utilities.transaction_base import validate_uom_is_integer + validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) + + def validate_bom_no(self): if self.doc.bom_no: bom = sql("""select name from `tabBOM` where name=%s and docstatus=1 and is_active=1 and item=%s""" @@ -38,16 +39,20 @@ class DocType: May be BOM not exists or inactive or not submitted or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1) + def validate_sales_order(self): if self.doc.sales_order: if not webnotes.conn.sql("""select name from `tabSales Order` where name=%s and docstatus = 1""", self.doc.sales_order): msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1) - + self.validate_production_order_against_so() - - from utilities.transaction_base import validate_uom_is_integer - validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) - + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + for w in [self.doc.fg_warehouse, self.doc.wip_warehouse]: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_production_order_against_so(self): # already ordered qty diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 1ccccdd2eb..435a9768aa 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -127,7 +127,7 @@ class DocType(SellingController): self.validate_po() self.validate_uom_is_integer("stock_uom", "qty") self.validate_for_items() - self.validate_warehouse_user() + self.validate_warehouse() sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_active_sales_items(self) sales_com_obj.check_conversion_rate(self) @@ -148,14 +148,15 @@ class DocType(SellingController): if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered' - def validate_warehouse_user(self): - from stock.utils import validate_warehouse_user + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company warehouses = list(set([d.reserved_warehouse for d in self.doclist.get({"doctype": self.tname}) if d.reserved_warehouse])) for w in warehouses: validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_with_previous_doc(self): super(DocType, self).validate_with_previous_doc(self.tname, { diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index 249062f29d..d1672ba12c 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -68,22 +68,14 @@ class DocType(BuyingController): self.doc.status = "Draft" import utilities - utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", - "Cancelled"]) + utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) - # restrict material request type self.validate_value("material_request_type", "in", ["Purchase", "Transfer"]) - # Get Purchase Common Obj pc_obj = get_obj(dt='Purchase Common') - - - # Validate for items pc_obj.validate_for_items(self) - - # Validate qty against SO - self.validate_qty_against_so() + self.validate_qty_against_so() def update_bin(self, is_submit, is_stopped): """ Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'""" diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index c29ca3a173..6fea546ba6 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -7,7 +7,6 @@ from webnotes import _, msgprint, ValidationError from webnotes.utils import cint, flt, getdate, cstr from webnotes.model.controller import DocListController -class InvalidWarehouseCompany(ValidationError): pass class SerialNoNotRequiredError(ValidationError): pass class SerialNoRequiredError(ValidationError): pass class SerialNoQtyError(ValidationError): pass @@ -25,7 +24,7 @@ class DocType(DocListController): self.doclist = doclist def validate(self): - from stock.utils import validate_warehouse_user + from stock.utils import validate_warehouse_user, validate_warehouse_company if not hasattr(webnotes, "new_stock_ledger_entries"): webnotes.new_stock_ledger_entries = [] @@ -33,7 +32,7 @@ class DocType(DocListController): self.validate_mandatory() self.validate_item() validate_warehouse_user(self.doc.warehouse) - self.validate_warehouse_company() + validate_warehouse_company(self.doc.warehouse, self.doc.company) self.scrub_posting_time() from accounts.utils import validate_fiscal_year @@ -63,13 +62,6 @@ class DocType(DocListController): as on %(posting_date)s %(posting_time)s""" % self.doc.fields) sself.doc.fields.pop('batch_bal') - - def validate_warehouse_company(self): - warehouse_company = webnotes.conn.get_value("Warehouse", self.doc.warehouse, "company") - if warehouse_company and warehouse_company != self.doc.company: - webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ - self.doc.warehouse + ", " + self.doc.company +")", - raise_exception=InvalidWarehouseCompany) def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] diff --git a/stock/utils.py b/stock/utils.py index 8836c6c991..1f501644ff 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -9,6 +9,7 @@ from webnotes.defaults import get_global_default from webnotes.utils.email_lib import sendmail class UserNotAllowedForWarehouse(webnotes.ValidationError): pass +class InvalidWarehouseCompany(webnotes.ValidationError): pass def get_stock_balance_on(warehouse, posting_date=None): if not posting_date: posting_date = nowdate() @@ -216,6 +217,12 @@ def validate_warehouse_user(warehouse): if warehouse_users and not (webnotes.session.user in warehouse_users): webnotes.throw(_("Not allowed entry in Warehouse") \ + ": " + warehouse, UserNotAllowedForWarehouse) + +def validate_warehouse_company(warehouse, company): + warehouse_company = webnotes.conn.get_value("Warehouse", warehouse, "company") + if warehouse_company and warehouse_company != company: + webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ + warehouse + ", " + company +")", raise_exception=InvalidWarehouseCompany) def get_sales_bom_buying_amount(item_code, warehouse, voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries, item_sales_bom): From 172edcecece6539ead608f424c348108ca684a57 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 7 Oct 2013 14:21:04 +0530 Subject: [PATCH 074/123] [docs] five day setup completed --- docs/user/docs.user.md | 14 +++++++------- .../docs.user.five_day_setup.day_1.md} | 8 ++++---- .../docs.user.five_day_setup.day_2.md} | 0 .../docs.user.five_day_setup.day_3.md} | 4 ++-- .../docs.user.five_day_setup.day_4.md} | 8 ++++---- .../docs.user.five_day_setup.day_5.md} | 2 +- .../docs.user.five_day_setup.md} | 12 ++++++------ 7 files changed, 24 insertions(+), 24 deletions(-) rename docs/user/{five_step_setup/docs.user.five.day_1.md => five_day_setup/docs.user.five_day_setup.day_1.md} (94%) rename docs/user/{five_step_setup/docs.user.five.day_2.md => five_day_setup/docs.user.five_day_setup.day_2.md} (100%) rename docs/user/{five_step_setup/docs.user.five.day_3.md => five_day_setup/docs.user.five_day_setup.day_3.md} (97%) rename docs/user/{five_step_setup/docs.user.five.day_4.md => five_day_setup/docs.user.five_day_setup.day_4.md} (92%) rename docs/user/{five_step_setup/docs.user.five.day_5.md => five_day_setup/docs.user.five_day_setup.day_5.md} (95%) rename docs/user/{five_step_setup/docs.user.five.md => five_day_setup/docs.user.five_day_setup.md} (76%) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 3aa3c9e414..53e5534185 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -3,7 +3,7 @@ "_label": "User Guide", "_toc": [ "docs.user.intro", - "docs.user.five", + "docs.user.five_day_setup", "docs.user.implement", "docs.user.setup", "docs.user.selling", @@ -30,12 +30,12 @@ Contents 1. [Open Source](docs.user.intro.open_source.html) 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) -1. [Five-Day-Setup](docs.user.five.html) - 1. [Day-1](docs.user.five.day_1.html) - 1. [Day-2](docs.user.five.day_2.html) - 1. [Day-3](docs.user.five.day_3.html) - 1. [Day-4](docs.user.five.day_4.html) - 1. [Day-5](docs.user.five.day_5.html) +1. [Five-Day-Setup](docs.user.five_day_setup.html) + 1. [Day-1](docs.user.five_day_setup.day_1.html) + 1. [Day-2](docs.user.five_day_setup.day_2.html) + 1. [Day-3](docs.user.five_day_setup.day_3.html) + 1. [Day-4](docs.user.five_day_setup.day_4.html) + 1. [Day-5](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md similarity index 94% rename from docs/user/five_step_setup/docs.user.five.day_1.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index d6786b40da..34f85dd911 100644 --- a/docs/user/five_step_setup/docs.user.five.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -26,20 +26,20 @@ After filling this form, you will get a pop-up message for completing the set-u The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon. -![Customer](img/firstdaysetup_customer.png) +![Customer](img/firstdaysetup-customer.png)
After clicking on Customer, a new form will appear.
-![Customer](img/firstdaysetup_customer_1.png) +![Customer](img/firstdaysetup-customer-1.png) To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system. Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup -![Main Menu](img/firstdaysetup_main_menu.png) +![Main Menu](img/firstdaysetup-main-menu.png)
@@ -48,7 +48,7 @@ Now proceed to make an Item. To go to the main menu, click on erpnext icon which On the setup page go to Item. -![Item](img/firstdaysetup_item.png) +![Item](img/firstdaysetup-item.png) Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers. diff --git a/docs/user/five_step_setup/docs.user.five.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md similarity index 100% rename from docs/user/five_step_setup/docs.user.five.day_2.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_2.md diff --git a/docs/user/five_step_setup/docs.user.five.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md similarity index 97% rename from docs/user/five_step_setup/docs.user.five.day_3.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index 09a5d3f4ac..dc7acef0fd 100644 --- a/docs/user/five_step_setup/docs.user.five.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -14,7 +14,7 @@ Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. -![Lead](img/thirddaysetup_lead.png) +![Lead](img/thirddaysetup-lead.png) Fill the Lead form. @@ -83,7 +83,7 @@ Save and Submit your Delivery Note to generate a Sales Invoice. You can also gen A Journal Voucher or a payment entry can be generated directly from the Sales Invoice. -![Payment Entry](img/thirddaysetup_payment_entry.png) +![Payment Entry](img/thirddaysetup-payment-entry.png) > To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md similarity index 92% rename from docs/user/five_step_setup/docs.user.five.day_4.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index d23fe54585..f4938e9c07 100644 --- a/docs/user/five_step_setup/docs.user.five.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -33,7 +33,7 @@ To go to Production Planning Tool, click on the Manufacturing Icon. On the Manuf To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. -![Production Order](img/fourthdaysetup_po.png) +![Production Order](img/fourthdaysetup-po.png)
@@ -43,7 +43,7 @@ To go to Production Order click on the Manufacturing Icon. On the Manufacturing To go to Stock Entry, click on the Stock Icon and go to Stock Entry. -![Stock Entry](img/fourthdaysetup_stock.png) +![Stock Entry](img/fourthdaysetup-stock.png)
@@ -69,7 +69,7 @@ To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Not To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. -![Warehouse](img/fourthdaysetup_warehouse.png) +![Warehouse](img/fourthdaysetup-warehouse.png)
@@ -84,7 +84,7 @@ Make a few Journal Vouchers. Generate some Accounting Reports. To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. -![Journal Voucher](img/fourthdaysetup_jv.png) +![Journal Voucher](img/fourthdaysetup-jv.png) > To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) diff --git a/docs/user/five_step_setup/docs.user.five.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md similarity index 95% rename from docs/user/five_step_setup/docs.user.five.day_5.md rename to docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index 30c64c3708..b69fccd6ed 100644 --- a/docs/user/five_step_setup/docs.user.five.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -14,7 +14,7 @@ Project is divided into Tasks and each Task is allocated to a resource. In ERPNe To create a Task, go to Project and click on Task. -![Tasks](img/fifthdaysetup_task.png) +![Tasks](img/fifthdaysetup-tasks.png)
diff --git a/docs/user/five_step_setup/docs.user.five.md b/docs/user/five_day_setup/docs.user.five_day_setup.md similarity index 76% rename from docs/user/five_step_setup/docs.user.five.md rename to docs/user/five_day_setup/docs.user.five_day_setup.md index 21170c5988..d296914f9e 100644 --- a/docs/user/five_step_setup/docs.user.five.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.md @@ -2,18 +2,18 @@ { "_label": "Five-Day Setup", "_toc": [ - "docs.user.five.day_1", - "docs.user.five.day_2", - "docs.user.five.day_3", - "docs.user.five.day_4", - "docs.user.five.day_5" + "docs.user.five_day_setup.day_1", + "docs.user.five_day_setup.day_2", + "docs.user.five_day_setup.day_3", + "docs.user.five_day_setup.day_4", + "docs.user.five_day_setup.day_5" ] } --- Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation. -The setup help is divided into day-wise instructions for 5 consecutive days. Day 1 will cover the following topics: +The setup help is divided into day-wise instructions for 5 consecutive days. #### Day 1 From 988096e82d6888544a4703a3f2ff65b4f790a08c Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 7 Oct 2013 18:06:52 +0530 Subject: [PATCH 075/123] [feature] Sales Funnel visualization. Go to Selling > Analytics > Sales Funnel --- .../{crm_funnel => sales_funnel}/__init__.py | 0 .../sales_funnel.css} | 0 .../sales_funnel.js} | 29 ++++++++++++++----- .../sales_funnel.py} | 0 .../sales_funnel.txt} | 8 ++--- selling/page/selling_home/selling_home.js | 4 +++ 6 files changed, 29 insertions(+), 12 deletions(-) rename selling/page/{crm_funnel => sales_funnel}/__init__.py (100%) rename selling/page/{crm_funnel/crm_funnel.css => sales_funnel/sales_funnel.css} (100%) rename selling/page/{crm_funnel/crm_funnel.js => sales_funnel/sales_funnel.js} (83%) rename selling/page/{crm_funnel/crm_funnel.py => sales_funnel/sales_funnel.py} (100%) rename selling/page/{crm_funnel/crm_funnel.txt => sales_funnel/sales_funnel.txt} (81%) diff --git a/selling/page/crm_funnel/__init__.py b/selling/page/sales_funnel/__init__.py similarity index 100% rename from selling/page/crm_funnel/__init__.py rename to selling/page/sales_funnel/__init__.py diff --git a/selling/page/crm_funnel/crm_funnel.css b/selling/page/sales_funnel/sales_funnel.css similarity index 100% rename from selling/page/crm_funnel/crm_funnel.css rename to selling/page/sales_funnel/sales_funnel.css diff --git a/selling/page/crm_funnel/crm_funnel.js b/selling/page/sales_funnel/sales_funnel.js similarity index 83% rename from selling/page/crm_funnel/crm_funnel.js rename to selling/page/sales_funnel/sales_funnel.js index a2d2b93479..e2c3a98bf5 100644 --- a/selling/page/crm_funnel/crm_funnel.js +++ b/selling/page/sales_funnel/sales_funnel.js @@ -1,14 +1,18 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. // License: GNU General Public License v3. See license.txt -wn.pages['crm-funnel'].onload = function(wrapper) { +wn.pages['sales-funnel'].onload = function(wrapper) { wn.ui.make_app_page({ parent: wrapper, - title: 'CRM Funnel', + title: 'Sales Funnel', single_column: true }); wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper); + + wrapper.appframe.add_module_icon("Selling", "sales-funnel", function() { + wn.set_route("selling-home"); + }); } erpnext.CRMFunnel = Class.extend({ @@ -40,8 +44,8 @@ erpnext.CRMFunnel = Class.extend({ .appendTo(this.elements.layout); this.options = { - from_date: wn.datetime.get_today(), - to_date: wn.datetime.add_months(wn.datetime.get_today(), -1) + from_date: wn.datetime.add_months(wn.datetime.get_today(), -1), + to_date: wn.datetime.get_today() }; // set defaults and bind on change @@ -108,7 +112,7 @@ erpnext.CRMFunnel = Class.extend({ y_old = y; // new y - y = y + (me.options.height * d.value / me.options.total_value); + y = y + d.height; // new x var half_side = (me.options.height - y) / Math.sqrt(3); @@ -122,15 +126,24 @@ erpnext.CRMFunnel = Class.extend({ }, prepare: function() { + var me = this; + this.elements.no_data.toggle(false); // calculate width and height options this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0; this.options.height = (Math.sqrt(3) * this.options.width) / 2.0; - // calculate total value - this.options.total_value = this.options.data.reduce( - function(prev, curr) { return prev + curr.value; }, 0.0); + // calculate total weightage + // as height decreases, area decreases by the square of the reduction + // hence, compensating by squaring the index value + this.options.total_weightage = this.options.data.reduce( + function(prev, curr, i) { return prev + Math.pow(i+1, 2) * curr.value; }, 0.0); + + // calculate height for each data + $.each(this.options.data, function(i, d) { + d.height = me.options.height * d.value * Math.pow(i+1, 2) / me.options.total_weightage; + }); this.elements.canvas = $('') .appendTo(this.elements.funnel_wrapper.empty()) diff --git a/selling/page/crm_funnel/crm_funnel.py b/selling/page/sales_funnel/sales_funnel.py similarity index 100% rename from selling/page/crm_funnel/crm_funnel.py rename to selling/page/sales_funnel/sales_funnel.py diff --git a/selling/page/crm_funnel/crm_funnel.txt b/selling/page/sales_funnel/sales_funnel.txt similarity index 81% rename from selling/page/crm_funnel/crm_funnel.txt rename to selling/page/sales_funnel/sales_funnel.txt index 29cf566053..b841f20fdc 100644 --- a/selling/page/crm_funnel/crm_funnel.txt +++ b/selling/page/sales_funnel/sales_funnel.txt @@ -11,21 +11,21 @@ "icon": "icon-filter", "module": "Selling", "name": "__common__", - "page_name": "crm-funnel", + "page_name": "sales-funnel", "standard": "Yes", - "title": "CRM Funnel" + "title": "Sales Funnel" }, { "doctype": "Page Role", "name": "__common__", - "parent": "crm-funnel", + "parent": "sales-funnel", "parentfield": "roles", "parenttype": "Page", "role": "Sales Manager" }, { "doctype": "Page", - "name": "crm-funnel" + "name": "sales-funnel" }, { "doctype": "Page Role" diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js index 9697ccf985..5dd33e640f 100644 --- a/selling/page/selling_home/selling_home.js +++ b/selling/page/selling_home/selling_home.js @@ -155,6 +155,10 @@ wn.module_page["Selling"] = [ "label":wn._("Sales Analytics"), page: "sales-analytics" }, + { + "label":wn._("Sales Funnel"), + page: "sales-funnel" + }, ] }, { From 8941841a9c289ff43e725e7eaca3c9371f7af369 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 7 Oct 2013 18:22:29 +0530 Subject: [PATCH 076/123] [setup wizard] added more steps [minor] [wip] --- public/js/utils.js | 2 +- setup/page/setup_wizard/setup_wizard.js | 141 +++++++++++++++++++----- 2 files changed, 113 insertions(+), 30 deletions(-) diff --git a/public/js/utils.js b/public/js/utils.js index 61e613bdec..6879b69e7a 100644 --- a/public/js/utils.js +++ b/public/js/utils.js @@ -20,7 +20,7 @@ $.extend(erpnext, { hide_company: function() { if(cur_frm.fields_dict.company) { - var companies = Object.keys(locals[":Company"]); + var companies = Object.keys(locals[":Company"] || {}); if(companies.length === 1) { if(!cur_frm.doc.company) cur_frm.set_value("company", companies[0]); cur_frm.toggle_display("company", false); diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js index b88f6e6c13..7ace2ef7bf 100644 --- a/setup/page/setup_wizard/setup_wizard.js +++ b/setup/page/setup_wizard/setup_wizard.js @@ -1,14 +1,18 @@ wn.pages['setup-wizard'].onload = function(wrapper) { + $(".navbar:first").toggle(false); + erpnext.wiz = new wn.wiz.Wizard({ parent: wrapper, title: wn._("ERPNext Setup Guide"), slides: [ // User { - title: wn._("The First User"), + title: wn._("The First User: You"), + icon: "icon-user", fields: [ {"fieldname": "first_name", "label": wn._("First Name"), "fieldtype": "Data", reqd:1}, {"fieldname": "last_name", "label": wn._("Last Name"), "fieldtype": "Data", reqd:1}, + {fieldtype:"Attach Image", fieldname:"attach_profile", label:"Attach Your Profile..."}, ], help: wn._('The first user will become the System Manager (you can change that later).') }, @@ -16,6 +20,7 @@ wn.pages['setup-wizard'].onload = function(wrapper) { // Organization { title: wn._("The Organization"), + icon: "icon-building", fields: [ {fieldname:'company_name', label: wn._('Company Name'), fieldtype:'Data', reqd:1, placeholder: 'e.g. "My Company LLC"'}, @@ -37,6 +42,7 @@ wn.pages['setup-wizard'].onload = function(wrapper) { // Country { title: wn._("Country, Timezone and Currency"), + icon: "icon-flag", fields: [ {fieldname:'country', label: wn._('Country'), reqd:1, options: "", fieldtype: 'Select'}, @@ -81,48 +87,122 @@ wn.pages['setup-wizard'].onload = function(wrapper) { // Logo { + icon: "icon-bookmark", title: wn._("Logo and Letter Heads"), help: wn._('Upload your letter head and logo - you can edit them later.'), - html: '

' + wn._('Upload Logo') + '


' - +'

' + wn._('Upload Letter Head') + '

', + fields: [ + {fieldtype:"Attach Image", fieldname:"attach_letterhead", label:"Attach Letterhead..."}, + {fieldtype:"Attach Image", fieldname:"attach_logo", label:"Attach Logo..."}, + ], + // html: '

' + wn._('Upload Logo') + '


' + // +'

' + wn._('Upload Letter Head') + '

', onload: function(slide) { - wn.upload.make({ - parent: slide.$wrapper.find(".upload-area-letter-head").css({"margin-left": "10px"}), - on_attach: function(fileobj) { - console.log(fileobj); - } - }); - - wn.upload.make({ - parent: slide.$wrapper.find(".upload-area-logo").css({"margin-left": "10px"}), - on_attach: function(fileobj) { - console.log(fileobj); - } - }); + // wn.upload.make({ + // parent: slide.$wrapper.find(".upload-area-letter-head").css({"margin-left": "10px"}), + // on_attach: function(fileobj) { + // console.log(fileobj); + // } + // }); + // + // wn.upload.make({ + // parent: slide.$wrapper.find(".upload-area-logo").css({"margin-left": "10px"}), + // on_attach: function(fileobj) { + // console.log(fileobj); + // } + // }); } }, // Taxes { + icon: "icon-money", "title": wn._("Add Taxes"), "help": wn._("List your tax heads (e.g. VAT, Excise) (upto 3) and their standard rates. This will create a standard template, you can edit and add more later."), "fields": [ + {fieldtype:"Column Break", fieldname:"cb_1", "label": "Tax Heads"}, {fieldtype:"Data", fieldname:"tax_1", label:"Tax 1", placeholder:"e.g. VAT"}, - {fieldtype:"Data", fieldname:"tax_rate_1", label:"Rate for Tax 1 (%)", placeholder:"e.g. 5"}, {fieldtype:"Data", fieldname:"tax_2", label:"Tax 2", placeholder:"e.g. Customs Duty"}, - {fieldtype:"Data", fieldname:"tax_rate_2", label:"Rate for Tax 2 (%)", placeholder:"e.g. 5"}, {fieldtype:"Data", fieldname:"tax_3", label:"Tax 3", placeholder:"e.g. Excise"}, - {fieldtype:"Data", fieldname:"tax_rate_3", label:"Rate for Tax 3 (%)", placeholder:"e.g. 5"}, + {fieldtype:"Column Break", fieldname:"cb_2", "label": "Tax Rates"}, + {fieldtype:"Data", fieldname:"tax_rate_1", label:"Rate (%)", placeholder:"e.g. 5"}, + {fieldtype:"Data", fieldname:"tax_rate_2", label:"Rate (%)", placeholder:"e.g. 5"}, + {fieldtype:"Data", fieldname:"tax_rate_3", label:"Rate (%)", placeholder:"e.g. 5"}, + ], + onload: function(slide) { + } + }, + + // Items to Sell + { + icon: "icon-barcode", + "title": wn._("Your Products or Services"), + "help": wn._("List your products or services that you sell to your customers."), + "fields": [ + {fieldtype:"Data", fieldname:"item_1", label:"Item 1", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_2", label:"Item 2", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_3", label:"Item 3", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_4", label:"Item 4", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_5", label:"Item 5", placeholder:"A Product or Service"}, + {fieldtype:"Column Break", fieldname:"cb_2", "label": "Attachments"}, + {fieldtype:"Attach", fieldname:"item_img_1", label:"Attach Image..."}, + {fieldtype:"Attach", fieldname:"item_img_2", label:"Attach Image..."}, + {fieldtype:"Attach", fieldname:"item_img_3", label:"Attach Image..."}, + {fieldtype:"Attach", fieldname:"item_img_4", label:"Attach Image..."}, + {fieldtype:"Attach", fieldname:"item_img_5", label:"Attach Image..."}, + ], + onload: function(slide) { + } + }, + + // Items to Buy + { + icon: "icon-barcode", + "title": wn._("Products or Services You Buy"), + "help": wn._("List a few products or services you buy from your suppliers or vendors. If these are same as your products, then do not add them."), + "fields": [ + {fieldtype:"Data", fieldname:"item_buy_1", label:"Item 1", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_buy_2", label:"Item 2", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_buy_3", label:"Item 3", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_buy_4", label:"Item 4", placeholder:"A Product or Service"}, + {fieldtype:"Data", fieldname:"item_buy_5", label:"Item 5", placeholder:"A Product or Service"}, + ], + onload: function(slide) { + } + }, + + // Customers + { + icon: "icon-group", + "title": wn._("Your Customers"), + "help": wn._("List a few of your customers. They could be organizations or individuals."), + "fields": [ + {fieldtype:"Data", fieldname:"customer_1", label:"Customer 1", placeholder:"Customer Name"}, + {fieldtype:"Data", fieldname:"customer_2", label:"Customer 2", placeholder:"Customer Name"}, + {fieldtype:"Data", fieldname:"customer_3", label:"Customer 3", placeholder:"Customer Name"}, + {fieldtype:"Data", fieldname:"customer_4", label:"Customer 4", placeholder:"Customer Name"}, + {fieldtype:"Data", fieldname:"customer_5", label:"Customer 5", placeholder:"Customer Name"}, + ], + onload: function(slide) { + } + }, + + // Suppliers + { + icon: "icon-group", + "title": wn._("Your Suppliers"), + "help": wn._("List a few of your suppliers. They could be organizations or individuals."), + "fields": [ + {fieldtype:"Data", fieldname:"supplier_1", label:"Supplier 1", placeholder:"Supplier Name"}, + {fieldtype:"Data", fieldname:"supplier_2", label:"Supplier 2", placeholder:"Supplier Name"}, + {fieldtype:"Data", fieldname:"supplier_3", label:"Supplier 3", placeholder:"Supplier Name"}, + {fieldtype:"Data", fieldname:"supplier_4", label:"Supplier 4", placeholder:"Supplier Name"}, + {fieldtype:"Data", fieldname:"supplier_5", label:"Supplier 5", placeholder:"Supplier Name"}, ], onload: function(slide) { - slide.form.fields_dict.tax_rate_1.$wrapper.css("margin-left", "50%"); - slide.form.fields_dict.tax_rate_2.$wrapper.css("margin-left", "50%"); - slide.form.fields_dict.tax_rate_3.$wrapper.css("margin-left", "50%"); } } - - // + ] }) @@ -163,20 +243,22 @@ wn.wiz.WizardSlide = Class.extend({ }, make: function() { var me = this; - this.$wrapper = $(repl('
\ -
%(main_title)s: %(title)s
\ + this.$wrapper = $(repl('
\ +
%(main_title)s: Step %(step)s
\
\
\
\
\ +

%(title)s


\
\
\ -

%(title)s

%(help)s

\ +

%(help)s

\
\
\ \
\ -
', {help:this.help, title:this.title, main_title:this.wiz.title, width: (flt(this.id + 1) / this.wiz.slides.length) * 100})) +
', {help:this.help, title:this.title, main_title:this.wiz.title, step: this.id + 1, + width: (flt(this.id + 1) / (this.wiz.slides.length+1)) * 100, icon:this.icon})) .appendTo(this.wiz.parent); this.body = this.$wrapper.find(".form")[0]; @@ -184,7 +266,8 @@ wn.wiz.WizardSlide = Class.extend({ if(this.fields) { this.form = new wn.ui.FieldGroup({ fields: this.fields, - body: this.body + body: this.body, + no_submit_on_enter: true }); this.form.make(); } else { From 8e65dae35cf700797baa240f83a82ee6d6914ea5 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 7 Oct 2013 19:25:50 +0530 Subject: [PATCH 077/123] [minor] [cleanup] add roles in setup control --- setup/doctype/setup_control/setup_control.py | 41 +++++++------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/setup/doctype/setup_control/setup_control.py b/setup/doctype/setup_control/setup_control.py index b78bfcc7d6..76818f0b4d 100644 --- a/setup/doctype/setup_control/setup_control.py +++ b/setup/doctype/setup_control/setup_control.py @@ -4,17 +4,16 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, cstr, getdate, now, nowdate, get_defaults -from webnotes.model.doc import Document, addchild -from webnotes.model.code import get_obj -from webnotes import session, form, msgprint +from webnotes.utils import cint, cstr, getdate, nowdate, get_defaults +from webnotes.model.doc import Document +from webnotes import msgprint class DocType: def __init__(self, d, dl): self.doc, self.doclist = d, dl def setup_account(self, args): - import webnotes, json + import json if isinstance(args, basestring): args = json.loads(args) webnotes.conn.begin() @@ -175,7 +174,6 @@ class DocType: system_managers = get_system_managers() if not system_managers: return - from webnotes.model.doc import Document for company in companies_list: if company and company[0]: edigest = webnotes.bean({ @@ -216,28 +214,19 @@ class DocType: abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:] return fy, stdt, abbr - def create_profile(self, user_email, user_fname, user_lname, pwd=None): - pr = Document('Profile') - pr.first_name = user_fname - pr.last_name = user_lname - pr.name = pr.email = user_email - pr.enabled = 1 - pr.save(1) - if pwd: - webnotes.conn.sql("""insert into __Auth (user, `password`) - values (%s, password(%s)) - on duplicate key update `password`=password(%s)""", - (user_email, pwd, pwd)) - - add_all_roles_to(pr.name) - -def add_all_roles_to(name): - profile = webnotes.doc("Profile", name) +def add_all_roles_to(profile): + if isinstance(profile, basestring): + profile = webnotes.bean("Profile", profile) + for role in webnotes.conn.sql("""select name from tabRole"""): if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]: - d = profile.addchild("user_roles", "UserRole") - d.role = role[0] - d.insert() + profile.doclist.append({ + "doctype": "UserRole", + "parentfield": "user_roles", + "role": role[0] + }) + + profile.save() def create_territories(): """create two default territories, one for home country and one named Rest of the World""" From 77f37e6b7c65586dfab58e31ad55d6f508d65180 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 8 Oct 2013 17:11:33 +0530 Subject: [PATCH 078/123] Update Serial No details through serial_no controller --- .../doctype/sales_invoice/sales_invoice.py | 2 - controllers/selling_controller.py | 32 +-- .../october_2013/p01_fix_serial_no_status.py | 37 +-- ...petual_inventory_stock_transfer_utility.py | 10 +- stock/doctype/delivery_note/delivery_note.py | 31 --- .../landed_cost_wizard/landed_cost_wizard.py | 2 - .../purchase_receipt/purchase_receipt.py | 21 +- stock/doctype/serial_no/serial_no.py | 223 ++++++++++++++++-- stock/doctype/stock_entry/stock_entry.py | 24 +- stock/doctype/stock_entry/test_stock_entry.py | 16 +- .../stock_ledger_entry/stock_ledger_entry.py | 126 +--------- 11 files changed, 250 insertions(+), 274 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 2eb9ae84cb..daf01ab801 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -83,7 +83,6 @@ class DocType(SellingController): def on_submit(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos() else: # Check for Approving Authority if not self.doc.recurring_id: @@ -111,7 +110,6 @@ class DocType(SellingController): def on_cancel(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos(cancel = True) sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index f1117ed177..37674ee4bf 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -233,34 +233,4 @@ class SellingController(StockController): self.doc.order_type = "Sales" elif self.doc.order_type not in valid_types: msgprint(_(self.meta.get_label("order_type")) + " " + - _("must be one of") + ": " + comma_or(valid_types), - raise_exception=True) - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, self.doc.doctype, self.fname) - update_serial_nos_after_submit(self, self.doc.doctype, "packing_details") - - for table_fieldname in (self.fname, "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = self.doc.doctype - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() + _("must be one of") + ": " + comma_or(valid_types), raise_exception=True) \ No newline at end of file diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py index 8700290fcd..38423281a1 100644 --- a/patches/october_2013/p01_fix_serial_no_status.py +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -6,35 +6,12 @@ import webnotes from webnotes.utils import flt def execute(): - serial_nos = webnotes.conn.sql("""select name, item_code, status from `tabSerial No` - where status!='Not in Use'""", as_dict=1) + serial_nos = webnotes.conn.sql("""select name from `tabSerial No` where status!='Not in Use' + and docstatus=0""") for sr in serial_nos: - last_sle = webnotes.conn.sql("""select voucher_type, voucher_no, actual_qty - from `tabStock Ledger Entry` where serial_no like %s and item_code=%s - order by name desc limit 1""", - ("%%%s%%" % sr.name, sr.item_code), as_dict=1) - - if flt(last_sle[0].actual_qty) > 0: - if last_sle[0].voucher_type == "Stock Entry" and webnotes.conn.get_value("Stock Entry", - last_sle[0].voucher_no, "purpose") == "Sales Return": - status = "Sales Returned" - else: - status = "Available" - else: - if last_sle[0].voucher_type == "Stock Entry": - purpose = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, "purpose") - if purpose == "Purchase Return": - status = "Purchase Returned" - else: - status = "Not Available" - else: - status = "Delivered" - if sr.status != status: - webnotes.conn.sql("""update `tabSerial No` set status=%s where name=%s""", - (status, sr.name)) + sr_bean = webnotes.bean("Serial No", sr[0]) + sr_bean.make_controller().via_stock_ledger = True + sr_bean.save() - webnotes.conn.sql("""update `tabSerial No` set warehouse='' - where status in ('Delivered', 'Purchase Returned')""") - - - \ No newline at end of file + webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in + ('Delivered', 'Purchase Returned')""") \ No newline at end of file diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py index 8cee29a824..d8cade78eb 100644 --- a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -29,9 +29,10 @@ def execute(): cost_center = "Default CC Ledger - NISL" for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!='' - and ifnull(warehouse, '')!='' and ifnull(actual_qty, 0) != 0 - and (select company from tabWarehouse where name=bin.warehouse)=%s""", - company[0], as_dict=1): + and ifnull(warehouse, '') in (%s) and ifnull(actual_qty, 0) != 0 + and (select company from tabWarehouse where name=bin.warehouse)=%s""" % + (', '.join(['%s']*len(warehouse_map)), '%s'), + (warehouse_map.keys() + [company[0]]), as_dict=1): item_details = item_map[bin.item_code] new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ if cstr(item_details.is_asset_item) == "Yes" \ @@ -40,7 +41,8 @@ def execute(): if item_details.has_serial_no == "Yes": serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name from `tabSerial No` where item_code = %s and warehouse = %s - and status='Available'""", (bin.item_code, bin.warehouse))]) + and status in ('Available', 'Sales Returned')""", + (bin.item_code, bin.warehouse))]) else: serial_no = None diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index e5e412e44b..2d1a3bece6 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -185,7 +185,6 @@ class DocType(SellingController): # create stock ledger entry self.update_stock_ledger() - self.update_serial_nos() self.credit_limit() @@ -203,42 +202,12 @@ class DocType(SellingController): self.update_prevdoc_status() self.update_stock_ledger() - self.update_serial_nos(cancel=True) webnotes.conn.set(self.doc, 'status', 'Cancelled') self.cancel_packing_slips() self.make_cancel_gl_entries() - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Delivery Note", "delivery_note_details") - update_serial_nos_after_submit(self, "Delivery Note", "packing_details") - - for table_fieldname in ("delivery_note_details", "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = "Delivery Note" - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() - def validate_packed_qty(self): """ Validate that if packed qty exists, it should be equal to qty diff --git a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py index 0924957338..89a3b81d57 100644 --- a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py +++ b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py @@ -85,7 +85,6 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty", is_cancelled="Yes") - pr_bean.run_method("update_serial_nos", cancel=True) webnotes.conn.sql("""delete from `tabStock Ledger Entry` where voucher_type='Purchase Receipt' and voucher_no=%s""", pr) @@ -97,5 +96,4 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty") pr_bean.run_method("update_stock") - pr_bean.run_method("update_serial_nos") pr_bean.run_method("make_gl_entries") \ No newline at end of file diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 7d663b8778..6169b1d916 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -246,26 +246,12 @@ class DocType(BuyingController): self.update_stock() - self.update_serial_nos() + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") purchase_controller.update_last_purchase_rate(self, 1) self.make_gl_entries() - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") - - for d in self.doclist.get({"parentfield": "purchase_receipt_details"}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.supplier = None - sr.doc.supplier_name = None - else: - sr.doc.supplier = self.doc.supplier - sr.doc.supplier_name = self.doc.supplier_name - sr.save() def check_next_docstatus(self): submit_rv = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % (self.doc.name)) @@ -292,7 +278,6 @@ class DocType(BuyingController): self.update_ordered_qty() self.update_stock() - self.update_serial_nos(cancel=True) self.update_prevdoc_status() pc_obj.update_last_purchase_rate(self, 0) @@ -308,7 +293,7 @@ class DocType(BuyingController): def get_rate(self,arg): return get_obj('Purchase Common').get_rate(arg,self) - + def get_gl_entries_for_stock(self, warehouse_account=None): against_stock_account = self.get_company_default("stock_received_but_not_billed") diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 1feab02cf5..c8b7222033 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -4,14 +4,22 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, getdate, nowdate +from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days import datetime -from webnotes import msgprint, _ +from webnotes import msgprint, _, ValidationError from controllers.stock_controller import StockController -class SerialNoCannotCreateDirectError(webnotes.ValidationError): pass -class SerialNoCannotCannotChangeError(webnotes.ValidationError): pass +class SerialNoCannotCreateDirectError(ValidationError): pass +class SerialNoCannotCannotChangeError(ValidationError): pass +class SerialNoNotRequiredError(ValidationError): pass +class SerialNoRequiredError(ValidationError): pass +class SerialNoQtyError(ValidationError): pass +class SerialNoItemError(ValidationError): pass +class SerialNoWarehouseError(ValidationError): pass +class SerialNoStatusError(ValidationError): pass +class SerialNoNotExistsError(ValidationError): pass +class SerialNoDuplicateError(ValidationError): pass class DocType(StockController): def __init__(self, doc, doclist=[]): @@ -21,13 +29,18 @@ class DocType(StockController): def validate(self): if self.doc.fields.get("__islocal") and self.doc.warehouse: - webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), - SerialNoCannotCreateDirectError) + webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be \ + set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError) self.validate_warranty_status() self.validate_amc_status() self.validate_warehouse() self.validate_item() + + if self.via_stock_ledger: + self.set_status() + self.set_purchase_details() + self.set_sales_details() def validate_amc_status(self): """ @@ -41,7 +54,8 @@ class DocType(StockController): validate warranty status """ if (self.doc.maintenance_status == 'Out of Warranty' and self.doc.warranty_expiry_date and getdate(self.doc.warranty_expiry_date) >= datetime.date.today()) or (self.doc.maintenance_status == 'Under Warranty' and (not self.doc.warranty_expiry_date or getdate(self.doc.warranty_expiry_date) < datetime.date.today())): - msgprint("Warranty expiry date and maintenance status mismatch. Please verify", raise_exception=1) + msgprint("Warranty expiry date and maintenance status mismatch. Please verify", + raise_exception=1) def validate_warehouse(self): @@ -49,10 +63,11 @@ class DocType(StockController): item_code, warehouse = webnotes.conn.get_value("Serial No", self.doc.name, ["item_code", "warehouse"]) if item_code != self.doc.item_code: - webnotes.throw(_("Item Code cannot be changed for Serial No."), SerialNoCannotCannotChangeError) + webnotes.throw(_("Item Code cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) if not self.via_stock_ledger and warehouse != self.doc.warehouse: - webnotes.throw(_("Warehouse cannot be changed for Serial No."), SerialNoCannotCannotChangeError) - + webnotes.throw(_("Warehouse cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) def validate_item(self): """ @@ -67,16 +82,89 @@ class DocType(StockController): self.doc.item_name = item.item_name self.doc.brand = item.brand self.doc.warranty_period = item.warranty_period + + def set_status(self): + last_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and ifnull(is_cancelled, 'No')='No' + order by name desc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + + if last_sle: + if last_sle[0].voucher_type == "Stock Entry": + document_type = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, + "purpose") + else: + document_type = last_sle[0].voucher_type + + if last_sle[0].actual_qty > 0: + if document_type == "Sales Return": + self.doc.status = "Sales Returned" + else: + self.doc.status = "Available" + else: + if document_type == "Purchase Return": + self.doc.status = "Purchase Returned" + elif last_sle[0].voucher_type in ("Delivery Note", "Sales Invoice"): + self.doc.status = "Delivered" + else: + self.doc.status = "Not Available" + + def set_purchase_details(self): + purchase_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty > 0 + and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + if purchase_sle: + self.doc.purchase_document_type = purchase_sle[0].voucher_type + self.doc.purchase_document_no = purchase_sle[0].voucher_no + self.doc.purchase_date = purchase_sle[0].posting_date + self.doc.purchase_time = purchase_sle[0].posting_time + self.doc.purchase_rate = purchase_sle[0].incoming_rate + if purchase_sle[0].voucher_type == "Purchase Receipt": + self.doc.supplier, self.doc.supplier_name = \ + webnotes.conn.get_value("Purchase Receipt", purchase_sle[0].voucher_no, + ["supplier_name", "supplier_name"]) + else: + for fieldname in ("purchase_document_type", "purchase_document_no", + "purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"): + self.doc.fields[fieldname] = None + + def set_sales_details(self): + delivery_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty<0 + and voucher_type in ('Delivery Note', 'Sales Invoice') + and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", + ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + self.doc.item_code), as_dict=1) + if delivery_sle: + self.doc.delivery_document_type = delivery_sle[0].voucher_type + self.doc.delivery_document_no = delivery_sle[0].voucher_no + self.doc.delivery_date = delivery_sle[0].posting_date + self.doc.delivery_time = delivery_sle[0].posting_time + self.doc.customer, self.doc.customer_name = \ + webnotes.conn.get_value(delivery_sle[0].voucher_type, delivery_sle[0].voucher_no, + ["customer", "customer_name"]) + if self.doc.warranty_period: + self.doc.warranty_expiry_date = add_days(cstr(delivery_sle[0].posting_date), + cint(self.doc.warranty_period)) + else: + for fieldname in ("delivery_document_type", "delivery_document_no", + "delivery_date", "delivery_time", "customer", "customer_name", + "warranty_expiry_date"): + self.doc.fields[fieldname] = None + def on_trash(self): if self.doc.status == 'Delivered': - msgprint("Cannot trash Serial No : %s as it is already Delivered" % (self.doc.name), raise_exception = 1) + webnotes.throw(_("Delivered Serial No ") + self.doc.name + _(" can not be deleted")) if self.doc.warehouse: - webnotes.throw(_("Cannot delete Serial No in warehouse. First remove from warehouse, then delete.") + \ - ": " + self.doc.name) - - def on_cancel(self): - self.on_trash() + webnotes.throw(_("Cannot delete Serial No in warehouse. \ + First remove from warehouse, then delete.") + ": " + self.doc.name) def on_rename(self, new, old, merge=False): """rename serial_no text fields""" @@ -93,3 +181,106 @@ class DocType(StockController): webnotes.conn.sql("""update `tab%s` set serial_no = %s where name=%s""" % (dt[0], '%s', '%s'), ('\n'.join(serial_nos), item[0])) + +def process_serial_no(sle): + item_det = get_item_details(sle.item_code) + validate_serial_no(sle, item_det) + update_serial_nos(sle, item_det) + +def validate_serial_no(sle, item_det): + if item_det.has_serial_no=="No": + if sle.serial_no: + webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + + sle.item_code), SerialNoNotRequiredError) + else: + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + if cint(sle.actual_qty) != flt(sle.actual_qty): + webnotes.throw(_("Serial No qty cannot be a fraction") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty))) + if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)): + webnotes.throw(_("Serial Nos do not match with qty") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty)), SerialNoQtyError) + + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + + if sr.doc.item_code!=sle.item_code: + webnotes.throw(_("Serial No does not belong to Item") + + (": %s (%s)" % (sle.item_code, serial_no)), SerialNoItemError) + + if sr.doc.warehouse and sle.actual_qty > 0: + webnotes.throw(_("Same Serial No") + ": " + sr.doc.name + + _(" can not be received twice"), SerialNoDuplicateError) + + if sle.actual_qty < 0: + if sr.doc.warehouse!=sle.warehouse: + webnotes.throw(_("Serial No") + ": " + serial_no + + _(" does not belong to Warehouse") + ": " + sle.warehouse, + SerialNoWarehouseError) + + if sle.voucher_type in ("Delivery Note", "Sales Invoice") \ + and sr.doc.status != "Available": + webnotes.throw(_("Serial No status must be 'Available' to Deliver") + + ": " + serial_no, SerialNoStatusError) + elif sle.actual_qty < 0: + # transfer out + webnotes.throw(_("Serial No must exist to transfer out.") + \ + ": " + serial_no, SerialNoNotExistsError) + elif not item_det.serial_no_series: + webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + + sle.item_code), SerialNoRequiredError) + +def update_serial_nos(sle, item_det): + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + sr.make_controller().via_stock_ledger = True + sr.doc.warehouse = sle.warehouse if sle.actual_qty > 0 else None + sr.save() + elif sle.actual_qty > 0: + make_serial_no(serial_no, sle) + elif sle.actual_qty > 0 and item_det.serial_no_series: + from webnotes.model.doc import make_autoname + serial_nos = [] + for i in xrange(cint(sle.actual_qty)): + serial_nos.append(make_serial_no(make_autoname(item_det.serial_no_series), sle)) + sle.serial_no = "\n".join(serial_nos) + +def get_item_details(item_code): + return webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", item_code, as_dict=True)[0] + +def get_serial_nos(serial_no): + return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] + +def make_serial_no(serial_no, sle): + sr = webnotes.new_bean("Serial No") + sr.doc.serial_no = serial_no + sr.doc.item_code = sle.item_code + sr.make_controller().via_stock_ledger = True + sr.insert() + sr.doc.warehouse = sle.warehouse + sr.doc.status = "Available" + sr.save() + webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) + return sr.doc.name + +def update_serial_nos_after_submit(controller, parenttype, parentfield): + if not hasattr(webnotes, "new_stock_ledger_entries"): + return + + for d in controller.doclist.get({"parentfield": parentfield}): + serial_no = None + for sle in webnotes.new_stock_ledger_entries: + if sle.voucher_detail_no==d.name: + serial_no = sle.serial_no + break + + if d.serial_no != serial_no: + d.serial_no = serial_no + webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index a54f9bf05b..8d2e76490c 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -52,13 +52,15 @@ class DocType(StockController): def on_submit(self): self.update_stock_ledger() - self.update_serial_no(1) + + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") + self.update_production_order(1) self.make_gl_entries() def on_cancel(self): self.update_stock_ledger() - self.update_serial_no(0) self.update_production_order(0) self.make_cancel_gl_entries() @@ -294,24 +296,6 @@ class DocType(StockController): from `tabStock Entry Detail` where parent in ( select name from `tabStock Entry` where `%s`=%s and docstatus=1) group by item_code""" % (ref_fieldname, "%s"), (self.doc.fields.get(ref_fieldname),))) - - def update_serial_no(self, is_submit): - """Create / Update Serial No""" - - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") - - for d in getlist(self.doclist, 'mtn_details'): - for serial_no in get_serial_nos(d.serial_no): - if self.doc.purpose == 'Purchase Return': - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Purchase Returned" if is_submit else "Available" - sr.save() - - if self.doc.purpose == "Sales Return": - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Sales Returned" if is_submit else "Delivered" - sr.save() def update_stock_ledger(self): sl_entries = [] diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index e2358eba4f..b41a6269ad 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import webnotes, unittest from webnotes.utils import flt -from stock.doctype.stock_ledger_entry.stock_ledger_entry import * +from stock.doctype.serial_no.serial_no import * from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory @@ -48,7 +48,7 @@ class TestStockEntry(unittest.TestCase): webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - from stock.doctype.stock_ledger_entry.stock_ledger_entry import InvalidWarehouseCompany + from stock.utils import InvalidWarehouseCompany st1 = webnotes.bean(copy=test_records[0]) st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() @@ -721,6 +721,18 @@ class TestStockEntry(unittest.TestCase): se.insert() self.assertRaises(SerialNoNotExistsError, se.submit) + def test_serial_duplicate(self): + self._clear_stock_account_balance() + self.test_serial_by_series() + + se = webnotes.bean(copy=test_records[0]) + se.doclist[1].item_code = "_Test Serialized Item With Series" + se.doclist[1].qty = 1 + se.doclist[1].serial_no = "ABCD00001" + se.doclist[1].transfer_qty = 1 + se.insert() + self.assertRaises(SerialNoDuplicateError, se.submit) + def test_serial_by_series(self): self._clear_stock_account_balance() se = make_serialized_item() diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 6fea546ba6..8fef889f72 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -3,21 +3,10 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint, ValidationError +from webnotes import _, msgprint from webnotes.utils import cint, flt, getdate, cstr from webnotes.model.controller import DocListController -class SerialNoNotRequiredError(ValidationError): pass -class SerialNoRequiredError(ValidationError): pass -class SerialNoQtyError(ValidationError): pass -class SerialNoItemError(ValidationError): pass -class SerialNoWarehouseError(ValidationError): pass -class SerialNoStatusError(ValidationError): pass -class SerialNoNotExistsError(ValidationError): pass - -def get_serial_nos(serial_no): - return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] - class DocType(DocListController): def __init__(self, doc, doclist=[]): self.doc = doc @@ -41,7 +30,9 @@ class DocType(DocListController): def on_submit(self): self.check_stock_frozen_date() self.actual_amt_check() - self.validate_serial_no() + + from stock.doctype.serial_no.serial_no import process_serial_no + process_serial_no(self.doc) #check for item quantity available in stock def actual_amt_check(self): @@ -73,7 +64,10 @@ class DocType(DocListController): msgprint("Warehouse: '%s' does not exist in the system. Please check." % self.doc.fields.get(k), raise_exception = 1) def validate_item(self): - item_det = self.get_item_details() + item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", + self.doc.item_code, as_dict=True)[0] if item_det.is_stock_item != 'Yes': webnotes.throw("""Item: "%s" is not a Stock Item.""" % self.doc.item_code) @@ -91,95 +85,6 @@ class DocType(DocListController): if not self.doc.stock_uom: self.doc.stock_uom = item_det.stock_uom - def get_item_details(self): - return webnotes.conn.sql("""select name, has_batch_no, docstatus, - is_stock_item, has_serial_no, serial_no_series - from tabItem where name=%s""", - self.doc.item_code, as_dict=True)[0] - - def validate_serial_no(self): - item_det = self.get_item_details() - - if item_det.has_serial_no=="No": - if self.doc.serial_no: - webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + self.doc.item), - SerialNoNotRequiredError) - else: - if self.doc.serial_no: - serial_nos = get_serial_nos(self.doc.serial_no) - if cint(self.doc.actual_qty) != flt(self.doc.actual_qty): - webnotes.throw(_("Serial No qty cannot be a fraction") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty))) - if len(serial_nos) and len(serial_nos) != abs(cint(self.doc.actual_qty)): - webnotes.throw(_("Serial Nos do not match with qty") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty)), SerialNoQtyError) - - # check serial no exists, if yes then source - for serial_no in serial_nos: - if webnotes.conn.exists("Serial No", serial_no): - sr = webnotes.bean("Serial No", serial_no) - - if sr.doc.item_code!=self.doc.item_code: - webnotes.throw(_("Serial No does not belong to Item") + \ - (": %s (%s)" % (self.doc.item_code, serial_no)), SerialNoItemError) - - sr.make_controller().via_stock_ledger = True - - if self.doc.actual_qty < 0: - if sr.doc.warehouse!=self.doc.warehouse: - webnotes.throw(_("Serial No") + ": " + serial_no + - _(" does not belong to Warehouse") + ": " + self.doc.warehouse, - SerialNoWarehouseError) - - if self.doc.voucher_type in ("Delivery Note", "Sales Invoice") \ - and sr.doc.status != "Available": - webnotes.throw(_("Serial No status must be 'Available' to Deliver") - + ": " + serial_no, SerialNoStatusError) - - - sr.doc.warehouse = None - sr.save() - else: - sr.doc.warehouse = self.doc.warehouse - sr.save() - else: - if self.doc.actual_qty < 0: - # transfer out - webnotes.throw(_("Serial No must exist to transfer out.") + \ - ": " + serial_no, SerialNoNotExistsError) - else: - # transfer in - self.make_serial_no(serial_no) - else: - if item_det.serial_no_series: - from webnotes.model.doc import make_autoname - serial_nos = [] - for i in xrange(cint(self.doc.actual_qty)): - serial_nos.append(self.make_serial_no(make_autoname(item_det.serial_no_series))) - self.doc.serial_no = "\n".join(serial_nos) - else: - webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item_code), - SerialNoRequiredError) - - def make_serial_no(self, serial_no): - sr = webnotes.new_bean("Serial No") - sr.doc.serial_no = serial_no - sr.doc.item_code = self.doc.item_code - sr.doc.purchase_rate = self.doc.incoming_rate - sr.doc.purchase_document_type = self.doc.voucher_type - sr.doc.purchase_document_no = self.doc.voucher_no - sr.doc.purchase_date = self.doc.posting_date - sr.doc.purchase_time = self.doc.posting_time - sr.make_controller().via_stock_ledger = True - sr.insert() - - # set warehouse - sr.doc.warehouse = self.doc.warehouse - sr.doc.status = "Available" - sr.save() - webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) - return sr.doc.name - def check_stock_frozen_date(self): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: @@ -191,21 +96,6 @@ class DocType(DocListController): if not self.doc.posting_time or self.doc.posting_time == '00:0': self.doc.posting_time = '00:00' -def update_serial_nos_after_submit(controller, parenttype, parentfield): - if not hasattr(webnotes, "new_stock_ledger_entries"): - return - - for d in controller.doclist.get({"parentfield": parentfield}): - serial_no = None - for sle in webnotes.new_stock_ledger_entries: - if sle.voucher_detail_no==d.name: - serial_no = sle.serial_no - break - - if d.serial_no != serial_no: - d.serial_no = serial_no - webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) - def on_doctype_update(): if not webnotes.conn.sql("""show index from `tabStock Ledger Entry` where Key_name="posting_sort_index" """): From 609046990b5544a6e5596780d162afcc80281ae7 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 8 Oct 2013 17:58:41 +0530 Subject: [PATCH 079/123] [fix] [minor] fix in serial no --- patches/october_2013/p01_fix_serial_no_status.py | 1 + stock/doctype/serial_no/serial_no.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py index 38423281a1..0bfc400a8e 100644 --- a/patches/october_2013/p01_fix_serial_no_status.py +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -11,6 +11,7 @@ def execute(): for sr in serial_nos: sr_bean = webnotes.bean("Serial No", sr[0]) sr_bean.make_controller().via_stock_ledger = True + sr_bean.run_method("validate") sr_bean.save() webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index c8b7222033..3922878280 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -88,7 +88,7 @@ class DocType(StockController): where (serial_no like %s or serial_no like %s or serial_no=%s) and item_code=%s and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) if last_sle: @@ -116,9 +116,9 @@ class DocType(StockController): where (serial_no like %s or serial_no like %s or serial_no=%s) and item_code=%s and actual_qty > 0 and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) - + if purchase_sle: self.doc.purchase_document_type = purchase_sle[0].voucher_type self.doc.purchase_document_no = purchase_sle[0].voucher_no @@ -128,7 +128,7 @@ class DocType(StockController): if purchase_sle[0].voucher_type == "Purchase Receipt": self.doc.supplier, self.doc.supplier_name = \ webnotes.conn.get_value("Purchase Receipt", purchase_sle[0].voucher_no, - ["supplier_name", "supplier_name"]) + ["supplier", "supplier_name"]) else: for fieldname in ("purchase_document_type", "purchase_document_no", "purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"): @@ -140,7 +140,7 @@ class DocType(StockController): and item_code=%s and actual_qty<0 and voucher_type in ('Delivery Note', 'Sales Invoice') and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", - ("%%%s%%" % self.doc.name+"\n", "%%%s%%" % "\n"+self.doc.name, self.doc.name, + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) if delivery_sle: self.doc.delivery_document_type = delivery_sle[0].voucher_type From 8c5a5f1ed5bf6f54adc04d337d15011856c7dca5 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 8 Oct 2013 17:59:11 +0530 Subject: [PATCH 080/123] New Setup Wizard --- .../june_2013/p08_shopping_cart_settings.py | 2 +- patches/patch_list.py | 1 + public/js/complete_setup.js | 126 ------- public/js/startup.js | 23 +- setup/doctype/company/company.txt | 4 +- setup/doctype/setup_control/README.md | 1 - setup/doctype/setup_control/__init__.py | 1 - setup/doctype/setup_control/setup_control.py | 255 ------------- setup/doctype/setup_control/setup_control.txt | 24 -- setup/page/setup_wizard/setup_wizard.js | 234 +++++++++--- setup/page/setup_wizard/setup_wizard.py | 349 ++++++++++++++++++ setup/page/setup_wizard/test_setup_data.py | 26 ++ setup/page/setup_wizard/test_setup_wizard.py | 14 + startup/install.py | 4 +- utilities/demo/make_demo.py | 3 +- utilities/doctype/contact/contact.txt | 6 +- 16 files changed, 589 insertions(+), 484 deletions(-) delete mode 100644 public/js/complete_setup.js delete mode 100644 setup/doctype/setup_control/README.md delete mode 100644 setup/doctype/setup_control/__init__.py delete mode 100644 setup/doctype/setup_control/setup_control.py delete mode 100644 setup/doctype/setup_control/setup_control.txt create mode 100644 setup/page/setup_wizard/setup_wizard.py create mode 100644 setup/page/setup_wizard/test_setup_data.py create mode 100644 setup/page/setup_wizard/test_setup_wizard.py diff --git a/patches/june_2013/p08_shopping_cart_settings.py b/patches/june_2013/p08_shopping_cart_settings.py index 479a6961e2..677b62a5e3 100644 --- a/patches/june_2013/p08_shopping_cart_settings.py +++ b/patches/june_2013/p08_shopping_cart_settings.py @@ -7,7 +7,7 @@ def execute(): webnotes.reload_doc("selling", "doctype", "shopping_cart_settings") # create two default territories, one for home country and one named Rest of the World - from setup.doctype.setup_control.setup_control import create_territories + from setup.page.setup_wizard.setup_wizard import create_territories create_territories() webnotes.conn.set_value("Shopping Cart Settings", None, "default_territory", "Rest of the World") diff --git a/patches/patch_list.py b/patches/patch_list.py index 1596a2870b..a5693854e5 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -223,4 +223,5 @@ patch_list = [ "patches.october_2013.p01_update_delivery_note_prevdocs", "patches.october_2013.p02_set_communication_status", "patches.october_2013.p03_crm_update_status", + "execute:webnotes.delete_doc('DocType', 'Setup Control')", ] \ No newline at end of file diff --git a/public/js/complete_setup.js b/public/js/complete_setup.js deleted file mode 100644 index e565621a2a..0000000000 --- a/public/js/complete_setup.js +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. -// License: GNU General Public License v3. See license.txt - -// complete my company registration -// -------------------------------- -wn.provide('erpnext.complete_setup'); - -$.extend(erpnext.complete_setup, { - show: function() { - d = erpnext.complete_setup.prepare_dialog(); - d.show(); - }, - - prepare_dialog: function() { - var d = new wn.ui.Dialog({ - title: "Setup", - fields: [ - {fieldname:'first_name', label:'Your First Name', fieldtype:'Data', reqd: 1}, - {fieldname:'last_name', label:'Your Last Name', fieldtype:'Data'}, - {fieldname:'company_name', label:'Company Name', fieldtype:'Data', reqd:1, - description: 'e.g. "My Company LLC"'}, - {fieldname:'company_abbr', label:'Company Abbreviation', fieldtype:'Data', - description:'e.g. "MC"',reqd:1}, - {fieldname:'fy_start', label:'Financial Year Start Date', fieldtype:'Select', - description:'Your financial year begins on"', reqd:1, - options: erpnext.complete_setup.fy_start_list.join('\n')}, - {fieldname:'country', label: 'Country', reqd:1, - options: "", fieldtype: 'Select'}, - {fieldname:'currency', label: 'Default Currency', reqd:1, - options: "", fieldtype: 'Select'}, - {fieldname:'timezone', label: 'Time Zone', reqd:1, - options: "", fieldtype: 'Select'}, - {fieldname:'industry', label: 'Industry', reqd:1, - options: erpnext.complete_setup.domains.join('\n'), fieldtype: 'Select'}, - {fieldname:'update', label:'Setup',fieldtype:'Button'}, - ], - }); - - if(user != 'Administrator'){ - d.$wrapper.find('.close').toggle(false); // Hide close image - $('header').toggle(false); // hide toolbar - } - - wn.call({ - method:"webnotes.country_info.get_country_timezone_info", - callback: function(data) { - erpnext.country_info = data.message.country_info; - erpnext.all_timezones = data.message.all_timezones; - d.get_input("country").empty() - .add_options([""].concat(keys(erpnext.country_info).sort())); - d.get_input("currency").empty() - .add_options(wn.utils.unique([""].concat($.map(erpnext.country_info, - function(opts, country) { return opts.currency; }))).sort()); - d.get_input("timezone").empty() - .add_options([""].concat(erpnext.all_timezones)); - } - }) - - // on clicking update - d.fields_dict.update.input.onclick = function() { - var data = d.get_values(); - if(!data) return; - $(this).set_working(); - return $c_obj('Setup Control','setup_account',data,function(r, rt){ - $(this).done_working(); - if(!r.exc) { - sys_defaults = r.message; - user_fullname = r.message.user_fullname; - wn.boot.user_info[user].fullname = user_fullname; - d.hide(); - $('header').toggle(true); - wn.container.wntoolbar.set_user_name(); - - setTimeout(function() { window.location.reload(); }, 3000); - } - }); - }; - - d.fields_dict.company_name.input.onchange = function() { - var parts = d.get_input("company_name").val().split(" "); - var abbr = $.map(parts, function(p) { return p ? p.substr(0,1) : null }).join(""); - d.get_input("company_abbr").val(abbr.toUpperCase()); - } - - d.fields_dict.country.input.onchange = function() { - var country = d.fields_dict.country.input.value; - var $timezone = $(d.fields_dict.timezone.input); - $timezone.empty(); - // add country specific timezones first - if(country){ - var timezone_list = erpnext.country_info[country].timezones || []; - $timezone.add_options(timezone_list.sort()); - - d.get_input("currency").val(erpnext.country_info[country].currency); - } - // add all timezones at the end, so that user has the option to change it to any timezone - $timezone.add_options([""].concat(erpnext.all_timezones)); - - }; - - // company name already set - if(wn.control_panel.company_name) { - var inp = d.fields_dict.company_name.input; - inp.value = wn.control_panel.company_name; - inp.disabled = true; - d.fields_dict.company_name.$input.trigger("change"); - } - - // set first name, last name - if(user_fullname) { - u = user_fullname.split(' '); - if(u[0]) { - d.fields_dict.first_name.input.value = u[0]; - } - if(u[1]) { - d.fields_dict.last_name.input.value = u[1]; - } - } - - return d; - }, - - fy_start_list: ['', '1st Jan', '1st Apr', '1st Jul', '1st Oct'], - - domains: ['', "Manufacturing", "Retail", "Distribution", "Services", "Other"], -}); \ No newline at end of file diff --git a/public/js/startup.js b/public/js/startup.js index eee8a05620..5a81d730a3 100644 --- a/public/js/startup.js +++ b/public/js/startup.js @@ -9,25 +9,10 @@ erpnext.startup.start = function() { console.log('Starting up...'); $('#startup_div').html('Starting up...').toggle(true); - if(user != 'Guest'){ - // setup toolbar - erpnext.toolbar.setup(); - - // complete registration - if(in_list(user_roles,'System Manager') && (wn.boot.setup_complete==='No')) { - wn.require("app/js/complete_setup.js"); - erpnext.complete_setup.show(); - } else if(!wn.boot.customer_count) { - if(wn.get_route()[0]!=="Setup") { - msgprint("" - + wn._("Proceed to Setup") + "\ -

"+ - wn._("This message goes away after you create your first customer.")+ - "

", wn._("Welcome")); - } - } else if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) { - erpnext.startup.show_expiry_banner(); - } + erpnext.toolbar.setup(); + + if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) { + erpnext.startup.show_expiry_banner(); } } diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt index 1ba1dde481..eb6b9ad35f 100644 --- a/setup/doctype/company/company.txt +++ b/setup/doctype/company/company.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 08:35:39", "docstatus": 0, - "modified": "2013-08-28 19:15:04", + "modified": "2013-10-08 15:18:34", "modified_by": "Administrator", "owner": "Administrator" }, @@ -80,7 +80,7 @@ "fieldtype": "Select", "label": "Domain", "options": "Distribution\nManufacturing\nRetail\nServices", - "reqd": 1 + "reqd": 0 }, { "doctype": "DocField", diff --git a/setup/doctype/setup_control/README.md b/setup/doctype/setup_control/README.md deleted file mode 100644 index 909fea49da..0000000000 --- a/setup/doctype/setup_control/README.md +++ /dev/null @@ -1 +0,0 @@ -Account setup utility on first login. \ No newline at end of file diff --git a/setup/doctype/setup_control/__init__.py b/setup/doctype/setup_control/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/setup/doctype/setup_control/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/setup/doctype/setup_control/setup_control.py b/setup/doctype/setup_control/setup_control.py deleted file mode 100644 index b78bfcc7d6..0000000000 --- a/setup/doctype/setup_control/setup_control.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. -# License: GNU General Public License v3. See license.txt - -from __future__ import unicode_literals -import webnotes - -from webnotes.utils import cint, cstr, getdate, now, nowdate, get_defaults -from webnotes.model.doc import Document, addchild -from webnotes.model.code import get_obj -from webnotes import session, form, msgprint - -class DocType: - def __init__(self, d, dl): - self.doc, self.doclist = d, dl - - def setup_account(self, args): - import webnotes, json - if isinstance(args, basestring): - args = json.loads(args) - webnotes.conn.begin() - - self.update_profile_name(args) - add_all_roles_to(webnotes.session.user) - self.create_fiscal_year_and_company(args) - self.set_defaults(args) - create_territories() - self.create_price_lists(args) - self.create_feed_and_todo() - self.create_email_digest() - - webnotes.clear_cache() - msgprint("Company setup is complete. This page will be refreshed in a moment.") - webnotes.conn.commit() - - return { - 'sys_defaults': get_defaults(), - 'user_fullname': (args.get('first_name') or '') + (args.get('last_name') - and (" " + args.get('last_name')) or '') - } - - def update_profile_name(self, args): - args['name'] = webnotes.session.get('user') - - # Update Profile - if not args.get('last_name') or args.get('last_name')=='None': args['last_name'] = None - webnotes.conn.sql("""\ - UPDATE `tabProfile` SET first_name=%(first_name)s, - last_name=%(last_name)s - WHERE name=%(name)s AND docstatus<2""", args) - - def create_fiscal_year_and_company(self, args): - curr_fiscal_year, fy_start_date, fy_abbr = self.get_fy_details(args.get('fy_start'), True) - webnotes.bean([{ - "doctype":"Fiscal Year", - 'year': curr_fiscal_year, - 'year_start_date': fy_start_date - }]).insert() - - curr_fiscal_year, fy_start_date, fy_abbr = self.get_fy_details(args.get('fy_start')) - webnotes.bean([{ - "doctype":"Fiscal Year", - 'year': curr_fiscal_year, - 'year_start_date': fy_start_date, - }]).insert() - - - # Company - webnotes.bean([{ - "doctype":"Company", - 'domain': args.get("industry"), - 'company_name':args.get('company_name'), - 'abbr':args.get('company_abbr'), - 'default_currency':args.get('currency'), - }]).insert() - - self.curr_fiscal_year = curr_fiscal_year - - def create_price_lists(self, args): - for pl_type in ["Selling", "Buying"]: - webnotes.bean([ - { - "doctype": "Price List", - "price_list_name": "Standard " + pl_type, - "buying_or_selling": pl_type, - "currency": args["currency"] - }, - { - "doctype": "For Territory", - "parentfield": "valid_for_territories", - "territory": "All Territories" - } - ]).insert() - - def set_defaults(self, args): - # enable default currency - webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1) - - global_defaults = webnotes.bean("Global Defaults", "Global Defaults") - global_defaults.doc.fields.update({ - 'current_fiscal_year': self.curr_fiscal_year, - 'default_currency': args.get('currency'), - 'default_company':args.get('company_name'), - 'date_format': webnotes.conn.get_value("Country", args.get("country"), "date_format"), - "float_precision": 4 - }) - global_defaults.save() - - accounts_settings = webnotes.bean("Accounts Settings") - accounts_settings.doc.auto_accounting_for_stock = 1 - accounts_settings.save() - - stock_settings = webnotes.bean("Stock Settings") - stock_settings.doc.item_naming_by = "Item Code" - stock_settings.doc.valuation_method = "FIFO" - stock_settings.doc.stock_uom = "Nos" - stock_settings.doc.auto_indent = 1 - stock_settings.save() - - selling_settings = webnotes.bean("Selling Settings") - selling_settings.doc.cust_master_name = "Customer Name" - selling_settings.doc.so_required = "No" - selling_settings.doc.dn_required = "No" - selling_settings.save() - - buying_settings = webnotes.bean("Buying Settings") - buying_settings.doc.supp_master_name = "Supplier Name" - buying_settings.doc.po_required = "No" - buying_settings.doc.pr_required = "No" - buying_settings.doc.maintain_same_rate = 1 - buying_settings.save() - - notification_control = webnotes.bean("Notification Control") - notification_control.doc.quotation = 1 - notification_control.doc.sales_invoice = 1 - notification_control.doc.purchase_order = 1 - notification_control.save() - - hr_settings = webnotes.bean("HR Settings") - hr_settings.doc.emp_created_by = "Naming Series" - hr_settings.save() - - # control panel - cp = webnotes.doc("Control Panel", "Control Panel") - for k in ['country', 'timezone', 'company_name']: - cp.fields[k] = args[k] - - cp.save() - - def create_feed_and_todo(self): - """update activty feed and create todo for creation of item, customer, vendor""" - import home - home.make_feed('Comment', 'ToDo', '', webnotes.session['user'], - '"' + 'Setup Complete. Please check your \ - To Do List' + '"', '#6B24B3') - - d = Document('ToDo') - d.description = 'Complete ERPNext Setup' - d.priority = 'High' - d.date = nowdate() - d.save(1) - - def create_email_digest(self): - """ - create a default weekly email digest - * Weekly Digest - * For all companies - * Recipients: System Managers - * Full content - * Enabled by default - """ - import webnotes - companies_list = webnotes.conn.sql("SELECT company_name FROM `tabCompany`", as_list=1) - - from webnotes.profile import get_system_managers - system_managers = get_system_managers() - if not system_managers: return - - from webnotes.model.doc import Document - for company in companies_list: - if company and company[0]: - edigest = webnotes.bean({ - "doctype": "Email Digest", - "name": "Default Weekly Digest - " + company[0], - "company": company[0], - "frequency": "Weekly", - "recipient_list": "\n".join(system_managers) - }) - - if webnotes.conn.sql("""select name from `tabEmail Digest` where name=%s""", edigest.doc.name): - continue - - for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}): - edigest.doc.fields[fieldname] = 1 - - edigest.insert() - - # Get Fiscal year Details - # ------------------------ - def get_fy_details(self, fy_start, last_year=False): - st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'} - if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]): - curr_year = getdate(nowdate()).year - 1 - else: - curr_year = getdate(nowdate()).year - - if last_year: - curr_year = curr_year - 1 - - stdt = cstr(curr_year)+'-'+cstr(st[fy_start]) - - if(fy_start == '1st Jan'): - fy = cstr(curr_year) - abbr = cstr(fy)[-2:] - else: - fy = cstr(curr_year) + '-' + cstr(curr_year+1) - abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:] - return fy, stdt, abbr - - def create_profile(self, user_email, user_fname, user_lname, pwd=None): - pr = Document('Profile') - pr.first_name = user_fname - pr.last_name = user_lname - pr.name = pr.email = user_email - pr.enabled = 1 - pr.save(1) - if pwd: - webnotes.conn.sql("""insert into __Auth (user, `password`) - values (%s, password(%s)) - on duplicate key update `password`=password(%s)""", - (user_email, pwd, pwd)) - - add_all_roles_to(pr.name) - -def add_all_roles_to(name): - profile = webnotes.doc("Profile", name) - for role in webnotes.conn.sql("""select name from tabRole"""): - if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]: - d = profile.addchild("user_roles", "UserRole") - d.role = role[0] - d.insert() - -def create_territories(): - """create two default territories, one for home country and one named Rest of the World""" - from setup.utils import get_root_of - country = webnotes.conn.get_value("Control Panel", None, "country") - root_territory = get_root_of("Territory") - for name in (country, "Rest Of The World"): - if name and not webnotes.conn.exists("Territory", name): - webnotes.bean({ - "doctype": "Territory", - "territory_name": name.replace("'", ""), - "parent_territory": root_territory, - "is_group": "No" - }).insert() - diff --git a/setup/doctype/setup_control/setup_control.txt b/setup/doctype/setup_control/setup_control.txt deleted file mode 100644 index 7ebed3e4a1..0000000000 --- a/setup/doctype/setup_control/setup_control.txt +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "creation": "2012-03-27 14:36:25", - "docstatus": 0, - "modified": "2012-03-27 14:36:25", - "modified_by": "Administrator", - "owner": "Administrator" - }, - { - "doctype": "DocType", - "in_create": 1, - "issingle": 1, - "istable": 0, - "module": "Setup", - "name": "__common__", - "read_only": 1, - "section_style": "Simple", - "version": 73 - }, - { - "doctype": "DocType", - "name": "Setup Control" - } -] \ No newline at end of file diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js index 7ace2ef7bf..25c95e0b0a 100644 --- a/setup/page/setup_wizard/setup_wizard.js +++ b/setup/page/setup_wizard/setup_wizard.js @@ -1,9 +1,59 @@ wn.pages['setup-wizard'].onload = function(wrapper) { + if(sys_defaults.company) { + wn.set_route("desktop"); + return; + } $(".navbar:first").toggle(false); + $("body").css({"padding-top":"30px"}); erpnext.wiz = new wn.wiz.Wizard({ + page_name: "setup-wizard", parent: wrapper, + on_complete: function(wiz) { + var values = wiz.get_values(); + wiz.show_working(); + console.log(values); + wn.call({ + method: "setup.page.setup_wizard.setup_wizard.setup_account", + args: values, + callback: function(r) { + if(r.exc) { + var d = msgprint(wn._("There were errors.")); + d.custom_onhide = function() { + wn.set_route(me.wiz.page_name, "0"); + } + } else { + wiz.show_complete(); + setTimeout(function() { + if(user==="Administrator") { + wn.msgprint(wn._("Login with your new User ID") + ":" + values.email); + setTimeout(function() { + wn.app.logout(); + }, 2000); + } else { + window.location = "app.html"; + } + }, 2000); + } + } + }) + }, title: wn._("ERPNext Setup Guide"), + welcome_html: '

\ +

'+wn._('ERPNext Setup')+'

\ +

' + + wn._('Welcome to ERPNext. Over the next few minutes we will help you setup your ERPNext account. Try and fill in as much information as you have even if it takes a bit longer. It will save you a lot of time later. Good Luck!') + + '

', + working_html: '

\ +

'+wn._('Setting up...')+'

\ +

' + + wn._('Sit tight while your system is being setup. This may take a few moments.') + + '

', + complete_html: '

\ +

'+wn._('Setup Complete!')+'

\ +

' + + wn._('Your setup is complete. Refreshing...') + + '

', slides: [ // User { @@ -12,9 +62,19 @@ wn.pages['setup-wizard'].onload = function(wrapper) { fields: [ {"fieldname": "first_name", "label": wn._("First Name"), "fieldtype": "Data", reqd:1}, {"fieldname": "last_name", "label": wn._("Last Name"), "fieldtype": "Data", reqd:1}, + {"email_id": "email", "label": wn._("Email Id"), "fieldtype": "Data", reqd:1, "description":"Your Login Id"}, + {"password": "password", "label": wn._("Password"), "fieldtype": "Password", reqd:1}, {fieldtype:"Attach Image", fieldname:"attach_profile", label:"Attach Your Profile..."}, ], - help: wn._('The first user will become the System Manager (you can change that later).') + help: wn._('The first user will become the System Manager (you can change that later).'), + onload: function(slide) { + if(user!=="Administrator") { + slide.form.fields_dict.password.$wrapper.toggle(false); + slide.form.fields_dict.email_id.$wrapper.toggle(false); + delete slide.form.fields_dict.email; + delete slide.form.fields_dict.password; + } + } }, // Organization @@ -26,8 +86,11 @@ wn.pages['setup-wizard'].onload = function(wrapper) { placeholder: 'e.g. "My Company LLC"'}, {fieldname:'company_abbr', label: wn._('Company Abbreviation'), fieldtype:'Data', placeholder:'e.g. "MC"',reqd:1}, + {fieldname:'fy_start', label:'Financial Year Start Date', fieldtype:'Select', + description:'Your financial year begins on', reqd:1, + options: ['', '1st Jan', '1st Apr', '1st Jul', '1st Oct'] }, {fieldname:'company_tagline', label: wn._('What does it do?'), fieldtype:'Data', - placeholder:'e.g. "Build tools for builders"',reqd:1}, + placeholder:'e.g. "Build tools for builders"', reqd:1}, ], help: wn._('The name of your company for which you are setting up this system.'), onload: function(slide) { @@ -94,24 +157,6 @@ wn.pages['setup-wizard'].onload = function(wrapper) { {fieldtype:"Attach Image", fieldname:"attach_letterhead", label:"Attach Letterhead..."}, {fieldtype:"Attach Image", fieldname:"attach_logo", label:"Attach Logo..."}, ], - // html: '

' + wn._('Upload Logo') + '


' - // +'

' + wn._('Upload Letter Head') + '

', - onload: function(slide) { - // wn.upload.make({ - // parent: slide.$wrapper.find(".upload-area-letter-head").css({"margin-left": "10px"}), - // on_attach: function(fileobj) { - // console.log(fileobj); - // } - // }); - // - // wn.upload.make({ - // parent: slide.$wrapper.find(".upload-area-logo").css({"margin-left": "10px"}), - // on_attach: function(fileobj) { - // console.log(fileobj); - // } - // }); - } - }, // Taxes @@ -120,39 +165,46 @@ wn.pages['setup-wizard'].onload = function(wrapper) { "title": wn._("Add Taxes"), "help": wn._("List your tax heads (e.g. VAT, Excise) (upto 3) and their standard rates. This will create a standard template, you can edit and add more later."), "fields": [ - {fieldtype:"Column Break", fieldname:"cb_1", "label": "Tax Heads"}, {fieldtype:"Data", fieldname:"tax_1", label:"Tax 1", placeholder:"e.g. VAT"}, - {fieldtype:"Data", fieldname:"tax_2", label:"Tax 2", placeholder:"e.g. Customs Duty"}, - {fieldtype:"Data", fieldname:"tax_3", label:"Tax 3", placeholder:"e.g. Excise"}, - {fieldtype:"Column Break", fieldname:"cb_2", "label": "Tax Rates"}, + {fieldtype:"Column Break"}, {fieldtype:"Data", fieldname:"tax_rate_1", label:"Rate (%)", placeholder:"e.g. 5"}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"tax_2", label:"Tax 2", placeholder:"e.g. Customs Duty"}, + {fieldtype:"Column Break"}, {fieldtype:"Data", fieldname:"tax_rate_2", label:"Rate (%)", placeholder:"e.g. 5"}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"tax_3", label:"Tax 3", placeholder:"e.g. Excise"}, + {fieldtype:"Column Break"}, {fieldtype:"Data", fieldname:"tax_rate_3", label:"Rate (%)", placeholder:"e.g. 5"}, ], - onload: function(slide) { - } }, // Items to Sell { icon: "icon-barcode", "title": wn._("Your Products or Services"), - "help": wn._("List your products or services that you sell to your customers."), + "help": wn._("List your products or services that you sell to your customers. Make sure to check the Item Group, Unit of Measure and other properties when you start."), "fields": [ {fieldtype:"Data", fieldname:"item_1", label:"Item 1", placeholder:"A Product or Service"}, - {fieldtype:"Data", fieldname:"item_2", label:"Item 2", placeholder:"A Product or Service"}, - {fieldtype:"Data", fieldname:"item_3", label:"Item 3", placeholder:"A Product or Service"}, - {fieldtype:"Data", fieldname:"item_4", label:"Item 4", placeholder:"A Product or Service"}, - {fieldtype:"Data", fieldname:"item_5", label:"Item 5", placeholder:"A Product or Service"}, - {fieldtype:"Column Break", fieldname:"cb_2", "label": "Attachments"}, + {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_1", label:"Attach Image..."}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"item_2", label:"Item 2", placeholder:"A Product or Service"}, + {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_2", label:"Attach Image..."}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"item_3", label:"Item 3", placeholder:"A Product or Service"}, + {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_3", label:"Attach Image..."}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"item_4", label:"Item 4", placeholder:"A Product or Service"}, + {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_4", label:"Attach Image..."}, + {fieldtype:"Section Break"}, + {fieldtype:"Data", fieldname:"item_5", label:"Item 5", placeholder:"A Product or Service"}, + {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_5", label:"Attach Image..."}, ], - onload: function(slide) { - } }, // Items to Buy @@ -167,8 +219,6 @@ wn.pages['setup-wizard'].onload = function(wrapper) { {fieldtype:"Data", fieldname:"item_buy_4", label:"Item 4", placeholder:"A Product or Service"}, {fieldtype:"Data", fieldname:"item_buy_5", label:"Item 5", placeholder:"A Product or Service"}, ], - onload: function(slide) { - } }, // Customers @@ -178,13 +228,25 @@ wn.pages['setup-wizard'].onload = function(wrapper) { "help": wn._("List a few of your customers. They could be organizations or individuals."), "fields": [ {fieldtype:"Data", fieldname:"customer_1", label:"Customer 1", placeholder:"Customer Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"customer_contact_1", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"customer_2", label:"Customer 2", placeholder:"Customer Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"customer_contact_2", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"customer_3", label:"Customer 3", placeholder:"Customer Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"customer_contact_3", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"customer_4", label:"Customer 4", placeholder:"Customer Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"customer_contact_4", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"customer_5", label:"Customer 5", placeholder:"Customer Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"customer_contact_5", label:"", placeholder:"Contact Name"}, ], - onload: function(slide) { - } }, // Suppliers @@ -194,13 +256,25 @@ wn.pages['setup-wizard'].onload = function(wrapper) { "help": wn._("List a few of your suppliers. They could be organizations or individuals."), "fields": [ {fieldtype:"Data", fieldname:"supplier_1", label:"Supplier 1", placeholder:"Supplier Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"supplier_contact_1", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"supplier_2", label:"Supplier 2", placeholder:"Supplier Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"supplier_contact_2", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"supplier_3", label:"Supplier 3", placeholder:"Supplier Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"supplier_contact_3", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"supplier_4", label:"Supplier 4", placeholder:"Supplier Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"supplier_contact_4", label:"", placeholder:"Contact Name"}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"supplier_5", label:"Supplier 5", placeholder:"Supplier Name"}, + {fieldtype:"Column Break"}, + {fieldtype:"Data", fieldname:"supplier_contact_5", label:"", placeholder:"Contact Name"}, ], - onload: function(slide) { - } } ] @@ -209,7 +283,8 @@ wn.pages['setup-wizard'].onload = function(wrapper) { } wn.pages['setup-wizard'].onshow = function(wrapper) { - erpnext.wiz.show(wn.get_route()[1] || "0"); + if(wn.get_route()[1]) + erpnext.wiz.show(wn.get_route()[1]); } wn.provide("wn.wiz"); @@ -217,10 +292,45 @@ wn.provide("wn.wiz"); wn.wiz.Wizard = Class.extend({ init: function(opts) { $.extend(this, opts); + this.slides = this.slides; this.slide_dict = {}; - wn.set_route("setup-wizard", "0"); + this.show_welcome(); + }, + get_message: function(html) { + return $(repl('
\ +
%(html)s
\ +
', {html:html})) + }, + show_welcome: function() { + if(this.$welcome) + return; + var me = this; + this.$welcome = this.get_message(this.welcome_html + + '

') + .appendTo(this.parent); + + this.$welcome.find(".btn").click(function() { + me.$welcome.toggle(false); + me.welcomed = true; + wn.set_route(me.page_name, "0"); + }) + + this.current_slide = {"$wrapper": this.$welcome}; + }, + show_working: function() { + this.hide_current_slide(); + wn.set_route(this.page_name); + this.current_slide = {"$wrapper": this.get_message(this.working_html).appendTo(this.parent)}; + }, + show_complete: function() { + this.hide_current_slide(); + this.current_slide = {"$wrapper": this.get_message(this.complete_html).appendTo(this.parent)}; }, show: function(id) { + if(!this.welcomed) { + wn.set_route(this.wiz.page_name); + return; + } id = cint(id); if(this.current_slide && this.current_slide.id===id) return; @@ -229,12 +339,24 @@ wn.wiz.Wizard = Class.extend({ this.slide_dict[id].make(); } - if(this.current_slide) - this.current_slide.$wrapper.toggle(false); + this.hide_current_slide(); this.current_slide = this.slide_dict[id]; this.current_slide.$wrapper.toggle(true); }, + hide_current_slide: function() { + if(this.current_slide) { + this.current_slide.$wrapper.toggle(false); + this.current_slide = null; + } + }, + get_values: function() { + var values = {}; + $.each(this.slide_dict, function(id, slide) { + $.extend(values, slide.values) + }) + return values; + } }); wn.wiz.WizardSlide = Class.extend({ @@ -249,10 +371,12 @@ wn.wiz.WizardSlide = Class.extend({
\
\
\ -

%(title)s


\
\
\ -

%(help)s

\ +
\ +

%(title)s


\ +

%(help)s

\ +
\
\
\ \ @@ -276,17 +400,29 @@ wn.wiz.WizardSlide = Class.extend({ if(this.id > 0) { this.$prev = $("") - .click(function() { wn.set_route("setup-wizard", me.id-1 + ""); }) + .click(function() { + wn.set_route(me.wiz.page_name, me.id-1 + ""); + }) .appendTo(this.$wrapper.find(".footer")) .css({"margin-right": "5px"}); } if(this.id+1 < this.wiz.slides.length) { this.$next = $("") - .click(function() { wn.set_route("setup-wizard", me.id+1 + ""); }) + .click(function() { + me.values = me.form.get_values(); + if(me.values===null) + return; + wn.set_route(me.wiz.page_name, me.id+1 + ""); + }) .appendTo(this.$wrapper.find(".footer")); } else { this.$complete = $("") - .click(function() { me.wiz.complete(); }).appendTo(this.$wrapper.find(".footer")); + .click(function() { + me.values = me.form.get_values(); + if(me.values===null) + return; + me.wiz.on_complete(me.wiz); + }).appendTo(this.$wrapper.find(".footer")); } if(this.onload) { diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py new file mode 100644 index 0000000000..3758b2d5bf --- /dev/null +++ b/setup/page/setup_wizard/setup_wizard.py @@ -0,0 +1,349 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes, json, base64 + +from webnotes.utils import cint, cstr, getdate, now, nowdate, get_defaults +from webnotes import _ +from webnotes.utils.file_manager import save_file + +@webnotes.whitelist() +def setup_account(args=None): + # if webnotes.conn.sql("select name from tabCompany"): + # webnotes.throw(_("Setup Already Complete!!")) + + if not args: + args = webnotes.local.form_dict + if isinstance(args, basestring): + args = json.loads(args) + + webnotes.conn.begin() + + update_profile_name(args) + create_fiscal_year_and_company(args) + set_defaults(args) + create_territories() + create_price_lists(args) + create_feed_and_todo() + create_email_digest() + create_taxes(args) + create_items(args) + create_customers(args) + create_suppliers(args) + webnotes.conn.set_value('Control Panel', None, 'home_page', 'desktop') + + webnotes.clear_cache() + webnotes.conn.commit() + + return "okay" + +def update_profile_name(args): + if args.get("email_id"): + args['name'] = args.get("email") + webnotes.mute_emails = True + webnotes.bean({ + "doctype":"Profile", + "email": args.get("email"), + "first_name": args.get("first_name"), + "last_name": args.get("last_name") + }).insert() + webnotes.mute_emails = False + from webnotes.auth import _update_password + _update_password(args.get("email"), args.get("password")) + + else: + args['name'] = webnotes.session.user + + # Update Profile + if not args.get('last_name') or args.get('last_name')=='None': + args['last_name'] = None + webnotes.conn.sql("""update `tabProfile` SET first_name=%(first_name)s, + last_name=%(last_name)s WHERE name=%(name)s""", args) + + if args.get("attach_profile"): + filename, filetype, content = args.get("attach_profile").split(",") + fileurl = save_file(filename, content, "Profile", args.get("name"), decode=True).file_name + webnotes.conn.set_value("Profile", args.get("name"), "user_image", fileurl) + + add_all_roles_to(args.get("name")) + +def create_fiscal_year_and_company(args): + curr_fiscal_year, fy_start_date, fy_abbr = get_fy_details(args.get('fy_start'), True) + webnotes.bean([{ + "doctype":"Fiscal Year", + 'year': curr_fiscal_year, + 'year_start_date': fy_start_date + }]).insert() + + curr_fiscal_year, fy_start_date, fy_abbr = get_fy_details(args.get('fy_start')) + webnotes.bean([{ + "doctype":"Fiscal Year", + 'year': curr_fiscal_year, + 'year_start_date': fy_start_date, + }]).insert() + + + # Company + webnotes.bean([{ + "doctype":"Company", + 'domain': args.get("industry"), + 'company_name':args.get('company_name'), + 'abbr':args.get('company_abbr'), + 'default_currency':args.get('currency'), + }]).insert() + + args["curr_fiscal_year"] = curr_fiscal_year + +def create_price_lists(args): + for pl_type in ["Selling", "Buying"]: + webnotes.bean([ + { + "doctype": "Price List", + "price_list_name": "Standard " + pl_type, + "buying_or_selling": pl_type, + "currency": args["currency"] + }, + { + "doctype": "For Territory", + "parentfield": "valid_for_territories", + "territory": "All Territories" + } + ]).insert() + +def set_defaults(args): + # enable default currency + webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1) + + global_defaults = webnotes.bean("Global Defaults", "Global Defaults") + global_defaults.doc.fields.update({ + 'current_fiscal_year': args.curr_fiscal_year, + 'default_currency': args.get('currency'), + 'default_company':args.get('company_name'), + 'date_format': webnotes.conn.get_value("Country", args.get("country"), "date_format"), + "float_precision": 4 + }) + global_defaults.save() + + accounts_settings = webnotes.bean("Accounts Settings") + accounts_settings.doc.auto_accounting_for_stock = 1 + accounts_settings.save() + + stock_settings = webnotes.bean("Stock Settings") + stock_settings.doc.item_naming_by = "Item Code" + stock_settings.doc.valuation_method = "FIFO" + stock_settings.doc.stock_uom = "Nos" + stock_settings.doc.auto_indent = 1 + stock_settings.save() + + selling_settings = webnotes.bean("Selling Settings") + selling_settings.doc.cust_master_name = "Customer Name" + selling_settings.doc.so_required = "No" + selling_settings.doc.dn_required = "No" + selling_settings.save() + + buying_settings = webnotes.bean("Buying Settings") + buying_settings.doc.supp_master_name = "Supplier Name" + buying_settings.doc.po_required = "No" + buying_settings.doc.pr_required = "No" + buying_settings.doc.maintain_same_rate = 1 + buying_settings.save() + + notification_control = webnotes.bean("Notification Control") + notification_control.doc.quotation = 1 + notification_control.doc.sales_invoice = 1 + notification_control.doc.purchase_order = 1 + notification_control.save() + + hr_settings = webnotes.bean("HR Settings") + hr_settings.doc.emp_created_by = "Naming Series" + hr_settings.save() + + # control panel + cp = webnotes.doc("Control Panel", "Control Panel") + for k in ['country', 'timezone', 'company_name']: + cp.fields[k] = args[k] + + cp.save() + +def create_feed_and_todo(): + """update activty feed and create todo for creation of item, customer, vendor""" + import home + home.make_feed('Comment', 'ToDo', '', webnotes.session['user'], + 'ERNext Setup Complete!', '#6B24B3') + +def create_email_digest(): + from webnotes.profile import get_system_managers + system_managers = get_system_managers() + if not system_managers: + return + + for company in webnotes.conn.sql_list("select name FROM `tabCompany`"): + if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company): + edigest = webnotes.bean({ + "doctype": "Email Digest", + "name": "Default Weekly Digest - " + company, + "company": company, + "frequency": "Weekly", + "recipient_list": "\n".join(system_managers) + }) + + for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}): + edigest.doc.fields[fieldname] = 1 + + edigest.insert() + +def get_fy_details(fy_start, last_year=False): + st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'} + if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]): + curr_year = getdate(nowdate()).year - 1 + else: + curr_year = getdate(nowdate()).year + + if last_year: + curr_year = curr_year - 1 + + stdt = cstr(curr_year)+'-'+cstr(st[fy_start]) + + if(fy_start == '1st Jan'): + fy = cstr(curr_year) + abbr = cstr(fy)[-2:] + else: + fy = cstr(curr_year) + '-' + cstr(curr_year+1) + abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:] + return fy, stdt, abbr + +def create_taxes(args): + for i in xrange(1,6): + if args.get("tax_" + str(i)): + webnotes.bean({ + "doctype":"Account", + "company": args.get("company_name"), + "parent_account": "Duties and Taxes - " + args.get("company_abbr"), + "account_name": args.get("tax_" + str(i)), + "group_or_ledger": "Ledger", + "is_pl_account": "No", + "account_type": "Tax", + "tax_rate": args.get("tax_rate_" + str(i)) + }).insert() + +def create_items(args): + for i in xrange(1,6): + item = args.get("item_" + str(i)) + if item: + webnotes.bean({ + "doctype":"Item", + "item_code": item, + "item_name": item, + "description": item, + "is_sales_item": "Yes", + "is_stock_item": "Yes", + "item_group":"Products", + "stock_uom": "Unit", + "default_warehouse": "Finished Goods - " + args.get("company_abbr") + }).insert() + + if args.get("item_img_" + str(i)): + filename, filetype, content = args.get("item_img_" + str(i)).split(",") + fileurl = save_file(filename, content, "Item", item, decode=True).file_name + webnotes.conn.set_value("Item", item, "image", fileurl) + + for i in xrange(1,6): + item = args.get("item_buy_" + str(i)) + if item: + webnotes.bean({ + "doctype":"Item", + "item_code": item, + "item_name": item, + "description": item, + "is_sales_item": "No", + "is_stock_item": "Yes", + "item_group":"Raw Material", + "stock_uom": "Unit", + "default_warehouse": "Stores - " + args.get("company_abbr") + }).insert() + + if args.get("item_img_" + str(i)): + filename, filetype, content = args.get("item_img_" + str(i)).split(",") + fileurl = save_file(filename, content, "Item", item, decode=True).file_name + webnotes.conn.set_value("Item", item, "image", fileurl) + + +def create_customers(args): + for i in xrange(1,6): + customer = args.get("customer_" + str(i)) + if customer: + webnotes.bean({ + "doctype":"Customer", + "customer_name": customer, + "customer_type": "Company", + "customer_group": "Commercial", + "territory": args.get("country"), + "company": args.get("company_name") + }).insert() + + if args.get("customer_contact_" + str(i)): + contact = args.get("customer_contact_" + str(i)).split(" ") + webnotes.bean({ + "doctype":"Contact", + "customer": customer, + "first_name":contact[0], + "last_name": len(contact) > 1 and contact[1] or "" + }).insert() + +def create_suppliers(args): + for i in xrange(1,6): + supplier = args.get("supplier_" + str(i)) + if supplier: + webnotes.bean({ + "doctype":"Supplier", + "supplier_name": supplier, + "supplier_type": "Local", + "company": args.get("company_name") + }).insert() + + if args.get("supplier_contact_" + str(i)): + contact = args.get("supplier_contact_" + str(i)).split(" ") + webnotes.bean({ + "doctype":"Contact", + "supplier": supplier, + "first_name":contact[0], + "last_name": len(contact) > 1 and contact[1] or "" + }).insert() + +def create_profile(user_email, user_fname, user_lname, pwd=None): + pr = webnotes.doc('Profile') + pr.first_name = user_fname + pr.last_name = user_lname + pr.name = pr.email = user_email + pr.enabled = 1 + pr.save(1) + if pwd: + webnotes.conn.sql("""insert into __Auth (user, `password`) + values (%s, password(%s)) + on duplicate key update `password`=password(%s)""", + (user_email, pwd, pwd)) + + add_all_roles_to(pr.name) + +def add_all_roles_to(name): + profile = webnotes.doc("Profile", name) + for role in webnotes.conn.sql("""select name from tabRole"""): + if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]: + d = profile.addchild("user_roles", "UserRole") + d.role = role[0] + d.insert() + +def create_territories(): + """create two default territories, one for home country and one named Rest of the World""" + from setup.utils import get_root_of + country = webnotes.conn.get_value("Control Panel", None, "country") + root_territory = get_root_of("Territory") + for name in (country, "Rest Of The World"): + if name and not webnotes.conn.exists("Territory", name): + webnotes.bean({ + "doctype": "Territory", + "territory_name": name.replace("'", ""), + "parent_territory": root_territory, + "is_group": "No" + }).insert() \ No newline at end of file diff --git a/setup/page/setup_wizard/test_setup_data.py b/setup/page/setup_wizard/test_setup_data.py new file mode 100644 index 0000000000..dcc6b0f5cb --- /dev/null +++ b/setup/page/setup_wizard/test_setup_data.py @@ -0,0 +1,26 @@ +args = { + "attach_letterhead": "erpnext.jpg,data:image/jpeg;base64,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WVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBGZVBZmCgAsxYgAKvLMSeAAOSTwO9AHxV4x/4KU/8E6Ph5rl74Y+IH7ff7FPgbxLps8ttqPh7xj+1R8C/DOuWFzA2ya3vdJ1rx3ZX9rPC/ySxT28ckbHa6g8UAcv/wAPYf8Agln/ANJK/wBgH/xMj9nX8f8Amo1ACf8AD2H/AIJZf9JLP2AP/EyP2de//dRu+f1oAX/h7D/wSz/6SV/sA/8AiZH7Ov8A88agA/4ew/8ABLP/AKSV/sA/+Jkfs7f/ADxqAD/h7D/wSz7/APBSv9gH/wATI/Z1/wDnjUAH/D2H/gln/wBJK/2AeOv/ABmR+zrx/wCZGoAP+HsP/BLP/pJX+wD/AOJkfs6//PGoA+hvg1+1N+zH+0al7J+z3+0b8B/jummxLcai/wAGvi98PviglhA7KqTXreCPEOuC1idnVVknKIzMoDEsMgHvHXmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAQkKCx6AEn6Dk0Af5wP/B1n/wAFovjN4n/aI8a/8E0v2evHOs+APgv8I7LRtO/aI1jwfqt7pGs/GL4ka/olh4ivPAmra1YPbXx+HHgDSdW03StS8L2s9taeI/Gs2vt4ni1Wz0LQIbUA/iMbnOV/75VRnkf3QM/U89SeaAGjrnB6senXI/yPegAHB6HkL+HH+c/jQApJOcqeAR9ckd/8+tAC55xg9euPf/Jz/wDroARuexPH/sw4/HH5c80AGfvHDc+31/yT7/mAL3A56k5xx/F/n/8AXQB6F8Kfi18TfgZ4/wDDHxU+Dvjvxb8MviN4N1ODV/C/jbwNruoeGfE+h39vIHjnsNY0qa3uowwXy7i3leW0u4Ge2vLe4tpZYmAP9ef/AIN/v+CpWs/8FUP2FdM+JXxLTS7b9oX4P+Kp/g98dl0i1i03T/EviPTdG0zW/DvxM03R7eNLXSbP4heG9St77UdPsUt9MsvGGm+LLPRrKz0a3sLaIA/cmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBCMgg9Dwfcd/wA6AP8AFM/4LVzzXH/BWv8A4KLvPI8rr+2J8d4VZzkiK28a6hbW8YP92GCGKJB/CiKO1AH5gc4P178Dkr1B555+vP8AeoAQZz/30Oo3Hjue+P0oAXn+R65PQc8fr/eHSgA556dPoOvcdc46n8KADnrjv3Pqf5eg659aAA5//Wf9rv6jB/DJHegBOfm6Z4789O/9emRmgBecj6nvx1bt6/5NABzx069zk/e556env2oA/wBDj/gx5mmf4Yf8FErdpGMEPjv9mqeKInKRzT+GPi/FPIo7PLHbQI57rEg/hoA/u7oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LS/8paf+CjPr/wANkfH3/wBTvVPf/wDX60AfmMc4Of8A638PU8H1/wA4oAQZyPXLc8dcc9+oP4GgAGc47kLnt0A98nvnj/64ApyScjsR147d+OvvjjmgAyc49we3r9c/Q9c8HrQAN7+/6sMDr7df60AHPzevGenp356EfzPXFABzkdcZPp1+b3z/AJ9aADnAHvknj+96e/8AkmgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M1AH939ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/ijf8ABaX/AJS0/wDBRn/s8j4+8/8Ac+ap3/zzQB+Y3+Prx1Ht/TqT60AIM+p/i53c+nPH5dcGgBec9+MdT+PoefXnoe+RQAvPX29ePr06/gaADBz1PXPX8x06fj+XWgBDn3/P1P8AnHXjIoAOeRz25z/9bvxnPqT9QA7g5PUjrx3P+fT8KADkfn1J56/5789OtAH+hn/wY7/8k3/4KL/9jr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8UX/AILS/wDKWn/gozxn/jMj4+9s/wDM+ap+fNAH5jEdeP8Ax0H+76/j+vpQAgHPT1/g/L3/AK9jQAd+hxx/APxoAO7cHv8AwD1/X/JoACOenf8AuZH59f8APFACkdePX+EH+L/D9OaAE7Hj0/gH4/8A1/060ALjnoOp/g7c9+n4/ie9ABj2/wDHPf8AT8e3PWgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M3+fegD+7+gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/xRf+C0v/KWn/goz/2eR8fffr481X/P55oA/Mc85P8AMH1HXuenP/6qAGjqOB1bnB75xn2Pbnp34NAC4Oc46Y7ZPAHTk/j+mTQAYPXA5z29wfm75/Dr3oAMHrhfXpz/ACz75657UABHt+nqwPPf/HnPNAAAeRgdeuODj/PPpk0AHcH/AGj2OepOeme/596ADHTgdR7H72eOvGPf1zQB/oaf8GO//JN/+Ci//Y6/syf+o38ZqAP7v6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAMzWda0jw7pOp69r+qadomiaLp97q+saxq99a6ZpWk6VptvJeajqep6jfTQWWn6fY2sUtzeX15PDa2sEbzTyxxqWAB+H/AMUv+DlH/giz8JfE194T139trwp4k1bTbmW0vp/hl4A+LfxT8PRzRMysLXxf4D8C654U1WLKnFxo+s6hbE8CY9wDzP8A4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAP8xH/AIKa/Gj4d/tF/wDBQn9s747/AAi1yTxN8MPi7+0n8XPiF4B8QTaVquhzaz4U8U+LL/VNE1J9H12007WdNa7sp45WstTsbS+t9xjubeGUFFAPho55+uc8e3v25/TnPUATJz27+mef+Bfn/XrQADIPYZx6c8fX/H+VAC5OfpnnjPb/AGvz6dqADJz/APqzj/vr8KAA5/rzj1Hv6fTmgBMnnp79P1+b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ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAf4ov8AwWk/5Sz/APBRrP8A0eT8f/8A1PdU/pn/ABoA/MY9fTnv/wAB75Pt/XvkATg9x/F+H6jr3yfpgcgAUfUdvqcYOP5YwfqTzQAHHJyffkZHPTOfU/8A1+xADj15znqM56Z69fXtj+HNAB+P5/73+POcYzjoOKADjnnuOhHp9evHHOOmckGgA79ecn69W/n3yMcn2AAAY459OMjHX6k/r168cUAf6Gn/AAY7/wDJN/8Agov/ANjr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LSf8pZ/+CjX/AGeT8f8A/wBT3VKAPzFJ5J9+/wBU70AGQe3Zsc+uc8Y/LP60AGf129+eAPbn8+DycA0AGeSe+PUdMj2wP1Pr2oAM8/8AAj375+np+GOPvUABP9T1/wBv/PJ/xoAM8Hp1Hf29+e3f8ehoAUfeHrk/zb/PX0oAQHgDscdSP73p1NAH+hr/AMGO/wDyTf8A4KL/APY6/syf+o38Zs0Af3f0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH+KL/wWj/5S0f8FGucf8Zk/H/r/wBj7qn/AOv9fqAfmOfbHXp+K+3uT+INADefUfxenb8PXk9c9aAF5yeR2z05yB7c5/Cg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BQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH/2Q==", + "attach_logo": "logo-2013-color-small.png,data:image/png;base64,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", + "attach_profile": "rushabh.jpeg,data:image/jpeg;base64,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", + "company_abbr": "WN", + "company_name": "Web Notes", + "company_tagline": "Open Source ERP", + "country": "India", + "currency": "INR", + "customer_1": "RIGPL", + "customer_2": "Mahesh Engg", + "customer_contact_1": "Aditya Duggal", + "customer_contact_2": "Mahesh Malani", + "first_name": "Rushabh", + "fy_start": "1st Apr", + "item_1": "Enterprise", + "item_2": "Small Business", + "item_3": "Solo", + "item_buy_1": "Adwords", + "item_buy_2": "Server Hosting", + "item_img_1": "logo-2013-color-small.png,data:image/png;base64,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", + "last_name": "Mehta", + "tax_1": "Service Tax", + "tax_rate_1": "12.5", + "timezone": "Asia/Calcutta" +} \ No newline at end of file diff --git a/setup/page/setup_wizard/test_setup_wizard.py b/setup/page/setup_wizard/test_setup_wizard.py new file mode 100644 index 0000000000..7f09a9bfea --- /dev/null +++ b/setup/page/setup_wizard/test_setup_wizard.py @@ -0,0 +1,14 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +from setup.page.setup_wizard.test_setup_data import args +from setup.page.setup_wizard.setup_wizard import setup_account + +if __name__=="__main__": + webnotes.connect() + webnotes.local.form_dict = webnotes._dict(args) + setup_account() + \ No newline at end of file diff --git a/startup/install.py b/startup/install.py index d79559426b..59b74965b9 100644 --- a/startup/install.py +++ b/startup/install.py @@ -13,13 +13,13 @@ def post_import(): import_country_and_currency() # home page - webnotes.conn.set_value('Control Panel', None, 'home_page', 'desktop') + webnotes.conn.set_value('Control Panel', None, 'home_page', 'setup-wizard') # features feature_setup() # all roles to Administrator - from setup.doctype.setup_control.setup_control import add_all_roles_to + from setup.page.setup_wizard.setup_wizard import add_all_roles_to add_all_roles_to("Administrator") webnotes.conn.commit() diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 692ae31110..62371a36c8 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -376,7 +376,8 @@ def install(): def complete_setup(): print "Complete Setup..." - webnotes.get_obj("Setup Control").setup_account({ + from setup.page.setup_wizard.setup_wizard import setup_account + setup_account({ "first_name": "Test", "last_name": "User", "fy_start": "1st Jan", diff --git a/utilities/doctype/contact/contact.txt b/utilities/doctype/contact/contact.txt index db23410820..199aaea82e 100644 --- a/utilities/doctype/contact/contact.txt +++ b/utilities/doctype/contact/contact.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-10 16:34:32", "docstatus": 0, - "modified": "2013-10-03 16:44:08", + "modified": "2013-10-08 16:48:50", "modified_by": "Administrator", "owner": "Administrator" }, @@ -85,7 +85,7 @@ "label": "Email Id", "oldfieldname": "email_id", "oldfieldtype": "Data", - "reqd": 1, + "reqd": 0, "search_index": 1 }, { @@ -95,7 +95,7 @@ "label": "Phone", "oldfieldname": "contact_no", "oldfieldtype": "Data", - "reqd": 1 + "reqd": 0 }, { "doctype": "DocField", From 5d455577297c50934ca40ad7ed0367127727a3cc Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 8 Oct 2013 18:23:05 +0530 Subject: [PATCH 081/123] [wsgi] [minor] fixed flags --- .../production_planning_tool/production_planning_tool.py | 4 ++-- setup/page/setup_wizard/setup_wizard.js | 3 +-- setup/page/setup_wizard/setup_wizard.py | 9 ++++++--- startup/__init__.py | 2 -- utilities/demo/make_demo.py | 6 +++--- utilities/demo/make_erpnext_demo.py | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 5480f177d9..6f15d4c9f1 100644 --- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -215,14 +215,14 @@ class DocType: pro = webnotes.new_bean("Production Order") pro.doc.fields.update(items[key]) - webnotes.mute_messages = True + webnotes.flags.mute_messages = True try: pro.insert() pro_list.append(pro.doc.name) except OverProductionError, e: pass - webnotes.mute_messages = False + webnotes.flags.mute_messages = False return pro_list diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js index 25c95e0b0a..905b6a9769 100644 --- a/setup/page/setup_wizard/setup_wizard.js +++ b/setup/page/setup_wizard/setup_wizard.js @@ -12,7 +12,6 @@ wn.pages['setup-wizard'].onload = function(wrapper) { on_complete: function(wiz) { var values = wiz.get_values(); wiz.show_working(); - console.log(values); wn.call({ method: "setup.page.setup_wizard.setup_wizard.setup_account", args: values, @@ -26,7 +25,7 @@ wn.pages['setup-wizard'].onload = function(wrapper) { wiz.show_complete(); setTimeout(function() { if(user==="Administrator") { - wn.msgprint(wn._("Login with your new User ID") + ":" + values.email); + msgprint(wn._("Login with your new User ID") + ":" + values.email); setTimeout(function() { wn.app.logout(); }, 2000); diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py index 3758b2d5bf..714df2ec0f 100644 --- a/setup/page/setup_wizard/setup_wizard.py +++ b/setup/page/setup_wizard/setup_wizard.py @@ -35,20 +35,23 @@ def setup_account(args=None): webnotes.clear_cache() webnotes.conn.commit() + + # suppress msgprints + webnotes.local.message_log = [] return "okay" def update_profile_name(args): - if args.get("email_id"): + if args.get("email"): args['name'] = args.get("email") - webnotes.mute_emails = True + webnotes.flags.mute_emails = True webnotes.bean({ "doctype":"Profile", "email": args.get("email"), "first_name": args.get("first_name"), "last_name": args.get("last_name") }).insert() - webnotes.mute_emails = False + webnotes.flags.mute_emails = False from webnotes.auth import _update_password _update_password(args.get("email"), args.get("password")) diff --git a/startup/__init__.py b/startup/__init__.py index 227846c46d..802daac9b3 100644 --- a/startup/__init__.py +++ b/startup/__init__.py @@ -27,8 +27,6 @@ profile_defaults = { "Territory": "territory" } -application_home_page = "desktop" - # add startup propertes mail_footer = """
Sent via ERPNext
""" diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 62371a36c8..d335528dfc 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -30,9 +30,9 @@ prob = { } def make(reset=False, simulate=True): - #webnotes.print_messages = True - webnotes.mute_emails = True - webnotes.rollback_on_exception = True + #webnotes.flags.print_messages = True + webnotes.flags.mute_emails = True + webnotes.flags.rollback_on_exception = True if not webnotes.conf.demo_db_name: raise Exception("conf.py does not have demo_db_name") diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index a57441b556..d67fb5ece0 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -6,7 +6,7 @@ import webnotes, os import utilities.demo.make_demo def make_demo_app(site=None): - webnotes.mute_emails = 1 + webnotes.flags.mute_emails = 1 webnotes.init(site=site) utilities.demo.make_demo.make(reset=True, simulate=False) From 94a9a479fedb4ef4986a60c71b5034529e341c72 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 11:16:08 +0530 Subject: [PATCH 082/123] [report] supplier addresses and contacts --- buying/page/buying_home/buying_home.js | 5 +++++ .../__init__.py | 0 .../supplier_addresses_and_contacts.txt | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 buying/report/supplier_addresses_and_contacts/__init__.py create mode 100644 buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js index 5db57f4f02..eec0725de9 100644 --- a/buying/page/buying_home/buying_home.js +++ b/buying/page/buying_home/buying_home.js @@ -145,6 +145,11 @@ wn.module_page["Buying"] = [ route: "query-report/Purchase Order Trends", doctype: "Purchase Order" }, + { + "label":wn._("Supplier Addresses And Contacts"), + route: "query-report/Supplier Addresses and Contacts", + doctype: "Supplier" + }, ] } ] diff --git a/buying/report/supplier_addresses_and_contacts/__init__.py b/buying/report/supplier_addresses_and_contacts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt new file mode 100644 index 0000000000..fac1e9e929 --- /dev/null +++ b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-10-09 10:38:40", + "docstatus": 0, + "modified": "2013-10-09 10:53:52", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc", + "ref_doctype": "Supplier", + "report_name": "Supplier Addresses and Contacts", + "report_type": "Query Report" + }, + { + "doctype": "Report", + "name": "Supplier Addresses and Contacts" + } +] \ No newline at end of file From 6ec7d9d3f95920dfc70b0a6c92697d1fa1bfe4a9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 11:46:50 +0530 Subject: [PATCH 083/123] [fix] [minor] item-wose tax in item-wise sales register --- .../item_wise_purchase_register.py | 4 ++-- .../item_wise_sales_register.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index bd0726e37d..1c3cef3115 100644 --- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -81,12 +81,12 @@ def get_tax_accounts(item_list, columns): if account_head not in tax_accounts: tax_accounts.append(account_head) - invoice = item_tax.setdefault(parent, {}) if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 77fb6f25e6..48bc463f14 100644 --- a/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -9,7 +9,7 @@ def execute(filters=None): if not filters: filters = {} columns = get_columns() last_col = len(columns) - + item_list = get_items(filters) item_tax, tax_accounts = get_tax_accounts(item_list, columns) @@ -21,7 +21,7 @@ def execute(filters=None): for tax in tax_accounts: row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0)) - + total_tax = sum(row[last_col:]) row += [total_tax, d.amount + total_tax] @@ -71,19 +71,19 @@ def get_tax_accounts(item_list, columns): tax_details = webnotes.conn.sql("""select parent, account_head, item_wise_tax_detail from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' and docstatus = 1 and ifnull(account_head, '') != '' - and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list])) + and parent in (%s)""" % ', '.join(['%s']*len(item_list)), + tuple([item.parent for item in item_list])) for parent, account_head, item_wise_tax_detail in tax_details: if account_head not in tax_accounts: tax_accounts.append(account_head) - - invoice = item_tax.setdefault(parent, {}) + if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) - + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue From 3235e787c4b32e243a6da97736f60a6d36a0f47c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 12:04:41 +0530 Subject: [PATCH 084/123] [fix] [minor] Pick cost_center from tax table for expense included in valuation --- .../purchase_invoice/purchase_invoice.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 7e19fb3ef9..3c3bcb7022 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -335,7 +335,7 @@ class DocType(BuyingController): ) # tax table gl entries - valuation_tax = 0 + valuation_tax = {} for tax in self.doclist.get({"parentfield": "purchase_tax_details"}): if tax.category in ("Total", "Valuation and Total") and flt(tax.tax_amount): gl_entries.append( @@ -350,8 +350,11 @@ class DocType(BuyingController): ) # accumulate valuation tax - if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount): - valuation_tax += (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) + if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount) \ + and tax.cost_center: + valuation_tax.setdefault(tax.cost_center, 0) + valuation_tax[tax.cost_center] += \ + (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) # item gl entries stock_item_and_auto_accounting_for_stock = False @@ -392,15 +395,19 @@ class DocType(BuyingController): if stock_item_and_auto_accounting_for_stock and valuation_tax: # credit valuation tax amount in "Expenses Included In Valuation" # this will balance out valuation amount included in cost of goods sold - gl_entries.append( - self.get_gl_dict({ - "account": self.get_company_default("expenses_included_in_valuation"), - "cost_center": self.get_company_default("cost_center"), - "against": self.doc.credit_to, - "credit": valuation_tax, - "remarks": self.doc.remarks or "Accounting Entry for Stock" - }) - ) + expenses_included_in_valuation = \ + self.get_company_default("expenses_included_in_valuation") + + for cost_center, amount in valuation_tax.items(): + gl_entries.append( + self.get_gl_dict({ + "account": expenses_included_in_valuation, + "cost_center": cost_center, + "against": self.doc.credit_to, + "credit": amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock" + }) + ) # writeoff account includes petty difference in the invoice amount # and the amount that is paid From 13bed4ef85f394b2c2012b35e7896e4c705f5d97 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 12:24:31 +0530 Subject: [PATCH 085/123] [fix] [minor] manitenance schedules report --- .../report/maintenance_schedules/maintenance_schedules.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/support/report/maintenance_schedules/maintenance_schedules.txt b/support/report/maintenance_schedules/maintenance_schedules.txt index 525f4834ba..766eb20151 100644 --- a/support/report/maintenance_schedules/maintenance_schedules.txt +++ b/support/report/maintenance_schedules/maintenance_schedules.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-06 14:25:21", "docstatus": 0, - "modified": "2013-05-06 14:32:47", + "modified": "2013-10-09 12:23:27", "modified_by": "Administrator", "owner": "Administrator" }, @@ -10,7 +10,7 @@ "doctype": "Report", "is_standard": "Yes", "name": "__common__", - "query": "SELECT\n ms_item.scheduled_date as \"Schedule Date:Date:120\",\n\tms_item.item_code as \"Item Code:Link/Item:120\",\n\tms_item.item_name as \"Item Name::120\",\n\tms_item.serial_no as \"Serial No::120\",\n\tms_item.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms.sales_order_no as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, `tabMaintenance Schedule Detail` ms_item\nWHERE\n\tms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_item.scheduled_date asc, ms_item.item_code asc", + "query": "SELECT\n ms_sch.scheduled_date as \"Schedule Date:Date:120\",\n\tms_sch.item_code as \"Item Code:Link/Item:120\",\n\tms_sch.item_name as \"Item Name::120\",\n\tms_sch.serial_no as \"Serial No::120\",\n\tms_sch.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms_item.prevdoc_docname as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, \n `tabMaintenance Schedule Detail` ms_sch, \n `tabMaintenance Schedule Item` ms_item\nWHERE\n\tms.name = ms_sch.parent and ms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_sch.scheduled_date asc, ms_sch.item_code asc", "ref_doctype": "Maintenance Schedule", "report_name": "Maintenance Schedules", "report_type": "Query Report" From 11faa57233f113d7123de17c6078271766265d95 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 13:21:36 +0530 Subject: [PATCH 086/123] [fix] [minor] fetching lead details in opportunity --- selling/doctype/lead/lead.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index 316481cbaa..41387f4938 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -133,4 +133,4 @@ def make_opportunity(source_name, target_doclist=None): } }}, target_doclist) - return [d.fields for d in doclist] \ No newline at end of file + return [d if isinstance(d, dict) else d.fields for d in doclist] \ No newline at end of file From 17c8b940e3ab44cafb311992f1d8788f745763e5 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 14:52:18 +0530 Subject: [PATCH 087/123] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 13 ++++--------- selling/doctype/quotation/quotation.py | 16 +--------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index c8c41e3f39..dfb124b448 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -70,10 +70,6 @@ class DocType(TransactionBase): return ret def on_update(self): - # Add to calendar - if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date: - webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date) - self.add_calendar_event() def add_calendar_event(self, opts=None, force=False): @@ -102,12 +98,11 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) def set_last_contact_date(self): - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref + if self.doc.contact_date: + if not self.doc.last_contact_date or (getdate(self.doc.last_contact_date) <= getdate(self.doc.contact_date)): + self.doc.last_contact_date = self.doc.contact_date else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception + webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) def validate_item_details(self): if not getlist(self.doclist, 'enquiry_details'): diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 44a67fa45c..8eb3654e62 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate +from webnotes.utils import cstr from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint @@ -93,19 +93,6 @@ class DocType(SellingController): msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation") raise Exception - #--------------Validation For Last Contact Date----------------- - # ==================================================================================================================== - def set_last_contact_date(self): - #if not self.doc.contact_date_ref: - #self.doc.contact_date_ref=self.doc.contact_date - #self.doc.last_contact_date=self.doc.contact_date_ref - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref - else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception - def validate(self): super(DocType, self).validate() @@ -116,7 +103,6 @@ class DocType(SellingController): utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Order Confirmed", "Order Lost", "Cancelled"]) - self.set_last_contact_date() self.validate_order_type() self.validate_for_items() From 3d72addae03b5010942eceff761f688a9a221613 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:01:17 +0530 Subject: [PATCH 088/123] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index dfb124b448..eaabd0836d 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -98,9 +98,9 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) def set_last_contact_date(self): - if self.doc.contact_date: - if not self.doc.last_contact_date or (getdate(self.doc.last_contact_date) <= getdate(self.doc.contact_date)): - self.doc.last_contact_date = self.doc.contact_date + if self._prev.contact_date: + if not self.doc.last_contact_date or (getdate(self._prev.contact_date) <= getdate(self.doc.contact_date)): + self.doc.last_contact_date = self._prev.contact_date else: webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) From 599fe0532a42a2fd458154aac510139e24025498 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:16:54 +0530 Subject: [PATCH 089/123] [minor] [fix] removed contact_date_ref --- selling/doctype/opportunity/opportunity.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index eaabd0836d..477521ca92 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -18,13 +18,6 @@ class DocType(TransactionBase): self.doclist = doclist self.fname = 'enq_details' self.tname = 'Opportunity Item' - - self._prev = webnotes._dict({ - "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - }) def get_item_details(self, item_code): item = sql("""select item_name, stock_uom, description_html, description, item_group, brand @@ -99,9 +92,9 @@ class DocType(TransactionBase): def set_last_contact_date(self): if self._prev.contact_date: - if not self.doc.last_contact_date or (getdate(self._prev.contact_date) <= getdate(self.doc.contact_date)): + if getdate(self._prev.contact_date) < getdate(self.doc.contact_date): self.doc.last_contact_date = self._prev.contact_date - else: + elif getdate(self._prev.contact_date) > getdate(self.doc.contact_date): webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) def validate_item_details(self): @@ -116,6 +109,13 @@ class DocType(TransactionBase): msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) def validate(self): + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") From 650cfc043489e1a21fadb94424d69e577214ac92 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:26:53 +0530 Subject: [PATCH 090/123] [minor] removed last_contact_date in opportunity --- selling/doctype/opportunity/opportunity.py | 24 +++++++-------------- selling/doctype/opportunity/opportunity.txt | 16 +------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index 477521ca92..5854758b5b 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate, cint +from webnotes.utils import cstr, cint from webnotes.model.bean import getlist from webnotes import msgprint @@ -19,6 +19,13 @@ class DocType(TransactionBase): self.fname = 'enq_details' self.tname = 'Opportunity Item' + self._prev = webnotes._dict({ + "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ + (not cint(self.doc.fields.get("__islocal"))) else None, + }) + def get_item_details(self, item_code): item = sql("""select item_name, stock_uom, description_html, description, item_group, brand from `tabItem` where name = %s""", item_code, as_dict=1) @@ -90,13 +97,6 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) - def set_last_contact_date(self): - if self._prev.contact_date: - if getdate(self._prev.contact_date) < getdate(self.doc.contact_date): - self.doc.last_contact_date = self._prev.contact_date - elif getdate(self._prev.contact_date) > getdate(self.doc.contact_date): - webnotes.throw(webnotes._("Contact Date Cannot be before Last Contact Date")) - def validate_item_details(self): if not getlist(self.doclist, 'enquiry_details'): msgprint("Please select items for which enquiry needs to be made") @@ -109,14 +109,6 @@ class DocType(TransactionBase): msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1) def validate(self): - self._prev = webnotes._dict({ - "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - "contact_by": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_by") if \ - (not cint(self.doc.fields.get("__islocal"))) else None, - }) - - self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") self.validate_lead_cust() diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index aeedd08bb8..8a68a31e79 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-09-25 19:32:29", + "modified": "2013-10-09 15:26:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -408,20 +408,6 @@ "oldfieldtype": "Date", "read_only": 0 }, - { - "allow_on_submit": 0, - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "to_discuss", From a0ecfba5f53d280291c9a25fb5fbbd89aca6e366 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 9 Oct 2013 15:28:16 +0530 Subject: [PATCH 091/123] [minor] removed last_contact_date from lead --- selling/doctype/lead/lead.txt | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index 408ad45125..b969906085 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-09-26 16:30:36", + "modified": "2013-10-09 15:27:54", "modified_by": "Administrator", "owner": "Administrator" }, @@ -174,19 +174,6 @@ "options": "Profile", "search_index": 1 }, - { - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "col_break123", From ddca90ef7b063e0846d59e71167a4b44e33e943a Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 9 Oct 2013 16:08:54 +0530 Subject: [PATCH 092/123] [communication] [setup wizard] [minor] [fixes] --- .../job_applicant/get_job_applications.py | 2 +- selling/doctype/customer/customer.js | 1 - selling/doctype/lead/get_leads.py | 2 +- setup/page/setup_wizard/setup_wizard.css | 8 ++ setup/page/setup_wizard/setup_wizard.js | 72 +++++++++++++++++- setup/page/setup_wizard/setup_wizard.py | 47 ++++++------ setup/page/setup_wizard/test_setup_data.py | 75 +++++++++++++------ startup/install.py | 1 + .../support_ticket/get_support_mails.py | 2 +- 9 files changed, 156 insertions(+), 54 deletions(-) create mode 100644 setup/page/setup_wizard/setup_wizard.css diff --git a/hr/doctype/job_applicant/get_job_applications.py b/hr/doctype/job_applicant/get_job_applications.py index 2e01328915..a929781019 100644 --- a/hr/doctype/job_applicant/get_job_applications.py +++ b/hr/doctype/job_applicant/get_job_applications.py @@ -37,7 +37,7 @@ class JobsMailbox(POP3Mailbox): mail.save_attachments_in_doc(applicant.doc) make(content=mail.content, sender=mail.from_email, - doctype="Job Applicant", name=applicant.doc.name) + doctype="Job Applicant", name=applicant.doc.name, sent_or_received="Received") def get_job_applications(): if cint(webnotes.conn.get_value('Jobs Email Settings', None, 'extract_emails')): diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js index d2c632530b..a38ab9cbf0 100644 --- a/selling/doctype/customer/customer.js +++ b/selling/doctype/customer/customer.js @@ -34,7 +34,6 @@ cur_frm.cscript.refresh = function(doc,dt,dn) { cur_frm.cscript.make_contact(doc,dt,dn); cur_frm.communication_view = new wn.views.CommunicationList({ - list: wn.model.get("Communication", {"customer": doc.name}), parent: cur_frm.fields_dict.communication_html.wrapper, doc: doc, }); diff --git a/selling/doctype/lead/get_leads.py b/selling/doctype/lead/get_leads.py index 3305a3b9f6..eaf837bb5b 100644 --- a/selling/doctype/lead/get_leads.py +++ b/selling/doctype/lead/get_leads.py @@ -29,7 +29,7 @@ def add_sales_communication(subject, content, sender, real_name, mail=None, parent_name = contact_name or lead_name message = make(content=content, sender=sender, subject=subject, - doctype = parent_doctype, name = parent_name, date=date) + doctype = parent_doctype, name = parent_name, date=date, sent_or_received="Received") if mail: # save attachments to parent if from mail diff --git a/setup/page/setup_wizard/setup_wizard.css b/setup/page/setup_wizard/setup_wizard.css new file mode 100644 index 0000000000..ad49ef0c04 --- /dev/null +++ b/setup/page/setup_wizard/setup_wizard.css @@ -0,0 +1,8 @@ +#page-setup-wizard .panel { + -webkit-box-shadow: 0px 1px 8px rgba(0,0,0,0.6); + box-shadow: 0px 1px 8px rgba(0,0,0,0.6); +} + +#page-setup-wizard .col-md-6 .control-input .btn { + width: 100%; +} diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js index 905b6a9769..648958e626 100644 --- a/setup/page/setup_wizard/setup_wizard.js +++ b/setup/page/setup_wizard/setup_wizard.js @@ -19,7 +19,7 @@ wn.pages['setup-wizard'].onload = function(wrapper) { if(r.exc) { var d = msgprint(wn._("There were errors.")); d.custom_onhide = function() { - wn.set_route(me.wiz.page_name, "0"); + wn.set_route(erpnext.wiz.page_name, "0"); } } else { wiz.show_complete(); @@ -61,8 +61,8 @@ wn.pages['setup-wizard'].onload = function(wrapper) { fields: [ {"fieldname": "first_name", "label": wn._("First Name"), "fieldtype": "Data", reqd:1}, {"fieldname": "last_name", "label": wn._("Last Name"), "fieldtype": "Data", reqd:1}, - {"email_id": "email", "label": wn._("Email Id"), "fieldtype": "Data", reqd:1, "description":"Your Login Id"}, - {"password": "password", "label": wn._("Password"), "fieldtype": "Password", reqd:1}, + {"fieldname": "email", "label": wn._("Email Id"), "fieldtype": "Data", reqd:1, "description":"Your Login Id"}, + {"fieldname": "password", "label": wn._("Password"), "fieldtype": "Password", reqd:1}, {fieldtype:"Attach Image", fieldname:"attach_profile", label:"Attach Your Profile..."}, ], help: wn._('The first user will become the System Manager (you can change that later).'), @@ -188,21 +188,51 @@ wn.pages['setup-wizard'].onload = function(wrapper) { {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_1", label:"Attach Image..."}, {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_group_1", options:["Products", "Services", "Raw Material", "Sub Assemblies"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_uom_1", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_2", label:"Item 2", placeholder:"A Product or Service"}, {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_2", label:"Attach Image..."}, {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_group_2", options:["Products", "Services", "Raw Material", "Sub Assemblies"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_uom_2", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_3", label:"Item 3", placeholder:"A Product or Service"}, {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_3", label:"Attach Image..."}, {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_group_3", options:["Products", "Services", "Raw Material", "Sub Assemblies"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_uom_3", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_4", label:"Item 4", placeholder:"A Product or Service"}, {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_4", label:"Attach Image..."}, {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_group_4", options:["Products", "Services", "Raw Material", "Sub Assemblies"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_uom_4", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_5", label:"Item 5", placeholder:"A Product or Service"}, {fieldtype:"Column Break"}, {fieldtype:"Attach", fieldname:"item_img_5", label:"Attach Image..."}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_group_5", options:["Products", "Services", "Raw Material", "Sub Assemblies"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_uom_5", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, ], }, @@ -213,10 +243,44 @@ wn.pages['setup-wizard'].onload = function(wrapper) { "help": wn._("List a few products or services you buy from your suppliers or vendors. If these are same as your products, then do not add them."), "fields": [ {fieldtype:"Data", fieldname:"item_buy_1", label:"Item 1", placeholder:"A Product or Service"}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_group_1", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_uom_1", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_buy_2", label:"Item 2", placeholder:"A Product or Service"}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_group_2", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_uom_2", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_buy_3", label:"Item 3", placeholder:"A Product or Service"}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_group_3", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_uom_3", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_buy_4", label:"Item 4", placeholder:"A Product or Service"}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_group_4", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_uom_4", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, + {fieldtype:"Section Break"}, {fieldtype:"Data", fieldname:"item_buy_5", label:"Item 5", placeholder:"A Product or Service"}, + {fieldtype:"Section Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_group_5", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]}, + {fieldtype:"Column Break"}, + {fieldtype:"Select", fieldname:"item_buy_uom_5", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]}, ], }, @@ -327,7 +391,7 @@ wn.wiz.Wizard = Class.extend({ }, show: function(id) { if(!this.welcomed) { - wn.set_route(this.wiz.page_name); + wn.set_route(this.page_name); return; } id = cint(id); diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py index 714df2ec0f..12767639c8 100644 --- a/setup/page/setup_wizard/setup_wizard.py +++ b/setup/page/setup_wizard/setup_wizard.py @@ -27,6 +27,7 @@ def setup_account(args=None): create_price_lists(args) create_feed_and_todo() create_email_digest() + create_letter_head(args) create_taxes(args) create_items(args) create_customers(args) @@ -234,16 +235,17 @@ def create_items(args): for i in xrange(1,6): item = args.get("item_" + str(i)) if item: + item_group = args.get("item_group_" + str(i)) webnotes.bean({ "doctype":"Item", "item_code": item, "item_name": item, "description": item, "is_sales_item": "Yes", - "is_stock_item": "Yes", - "item_group":"Products", - "stock_uom": "Unit", - "default_warehouse": "Finished Goods - " + args.get("company_abbr") + "is_stock_item": item_group!="Services" and "Yes" or "No", + "item_group": item_group, + "stock_uom": args.get("item_uom_" + str(i)), + "default_warehouse": item_group!="Service" and ("Finished Goods - " + args.get("company_abbr")) or "" }).insert() if args.get("item_img_" + str(i)): @@ -254,16 +256,17 @@ def create_items(args): for i in xrange(1,6): item = args.get("item_buy_" + str(i)) if item: + item_group = args.get("item_buy_group_" + str(i)) webnotes.bean({ "doctype":"Item", "item_code": item, "item_name": item, "description": item, "is_sales_item": "No", - "is_stock_item": "Yes", - "item_group":"Raw Material", - "stock_uom": "Unit", - "default_warehouse": "Stores - " + args.get("company_abbr") + "is_stock_item": item_group!="Services" and "Yes" or "No", + "item_group": item_group, + "stock_uom": args.get("item_buy_uom_" + str(i)), + "default_warehouse": item_group!="Service" and ("Stores - " + args.get("company_abbr")) or "" }).insert() if args.get("item_img_" + str(i)): @@ -314,20 +317,20 @@ def create_suppliers(args): "last_name": len(contact) > 1 and contact[1] or "" }).insert() -def create_profile(user_email, user_fname, user_lname, pwd=None): - pr = webnotes.doc('Profile') - pr.first_name = user_fname - pr.last_name = user_lname - pr.name = pr.email = user_email - pr.enabled = 1 - pr.save(1) - if pwd: - webnotes.conn.sql("""insert into __Auth (user, `password`) - values (%s, password(%s)) - on duplicate key update `password`=password(%s)""", - (user_email, pwd, pwd)) - - add_all_roles_to(pr.name) + +def create_letter_head(args): + if args.get("attach_letterhead"): + lh = webnotes.bean({ + "doctype":"Letter Head", + "letter_head_name": "Standard", + "is_default": 1 + }).insert() + + filename, filetype, content = args.get("attach_letterhead").split(",") + fileurl = save_file(filename, content, "Letter Head", "Standard", decode=True).file_name + webnotes.conn.set_value("Letter Head", "Standard", "content", "" % fileurl) + + def add_all_roles_to(name): profile = webnotes.doc("Profile", name) diff --git a/setup/page/setup_wizard/test_setup_data.py b/setup/page/setup_wizard/test_setup_data.py index dcc6b0f5cb..b5b6359893 100644 --- a/setup/page/setup_wizard/test_setup_data.py +++ b/setup/page/setup_wizard/test_setup_data.py @@ -1,26 +1,53 @@ + args = { - "attach_letterhead": "erpnext.jpg,data:image/jpeg;base64,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WVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBGZVBZmCgAsxYgAKvLMSeAAOSTwO9AHxV4x/4KU/8E6Ph5rl74Y+IH7ff7FPgbxLps8ttqPh7xj+1R8C/DOuWFzA2ya3vdJ1rx3ZX9rPC/ySxT28ckbHa6g8UAcv/wAPYf8Agln/ANJK/wBgH/xMj9nX8f8Amo1ACf8AD2H/AIJZf9JLP2AP/EyP2de//dRu+f1oAX/h7D/wSz/6SV/sA/8AiZH7Ov8A88agA/4ew/8ABLP/AKSV/sA/+Jkfs7f/ADxqAD/h7D/wSz7/APBSv9gH/wATI/Z1/wDnjUAH/D2H/gln/wBJK/2AeOv/ABmR+zrx/wCZGoAP+HsP/BLP/pJX+wD/AOJkfs6//PGoA+hvg1+1N+zH+0al7J+z3+0b8B/jummxLcai/wAGvi98PviglhA7KqTXreCPEOuC1idnVVknKIzMoDEsMgHvHXmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAQkKCx6AEn6Dk0Af5wP/B1n/wAFovjN4n/aI8a/8E0v2evHOs+APgv8I7LRtO/aI1jwfqt7pGs/GL4ka/olh4ivPAmra1YPbXx+HHgDSdW03StS8L2s9taeI/Gs2vt4ni1Wz0LQIbUA/iMbnOV/75VRnkf3QM/U89SeaAGjrnB6senXI/yPegAHB6HkL+HH+c/jQApJOcqeAR9ckd/8+tAC55xg9euPf/Jz/wDroARuexPH/sw4/HH5c80AGfvHDc+31/yT7/mAL3A56k5xx/F/n/8AXQB6F8Kfi18TfgZ4/wDDHxU+Dvjvxb8MviN4N1ODV/C/jbwNruoeGfE+h39vIHjnsNY0qa3uowwXy7i3leW0u4Ge2vLe4tpZYmAP9ef/AIN/v+CpWs/8FUP2FdM+JXxLTS7b9oX4P+Kp/g98dl0i1i03T/EviPTdG0zW/DvxM03R7eNLXSbP4heG9St77UdPsUt9MsvGGm+LLPRrKz0a3sLaIA/cmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBCMgg9Dwfcd/wA6AP8AFM/4LVzzXH/BWv8A4KLvPI8rr+2J8d4VZzkiK28a6hbW8YP92GCGKJB/CiKO1AH5gc4P178Dkr1B555+vP8AeoAQZz/30Oo3Hjue+P0oAXn+R65PQc8fr/eHSgA556dPoOvcdc46n8KADnrjv3Pqf5eg659aAA5//Wf9rv6jB/DJHegBOfm6Z4789O/9emRmgBecj6nvx1bt6/5NABzx069zk/e556env2oA/wBDj/gx5mmf4Yf8FErdpGMEPjv9mqeKInKRzT+GPi/FPIo7PLHbQI57rEg/hoA/u7oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LS/8paf+CjPr/wANkfH3/wBTvVPf/wDX60AfmMc4Of8A638PU8H1/wA4oAQZyPXLc8dcc9+oP4GgAGc47kLnt0A98nvnj/64ApyScjsR147d+OvvjjmgAyc49we3r9c/Q9c8HrQAN7+/6sMDr7df60AHPzevGenp356EfzPXFABzkdcZPp1+b3z/AJ9aADnAHvknj+96e/8AkmgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M1AH939ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/ijf8ABaX/AJS0/wDBRn/s8j4+8/8Ac+ap3/zzQB+Y3+Prx1Ht/TqT60AIM+p/i53c+nPH5dcGgBec9+MdT+PoefXnoe+RQAvPX29ePr06/gaADBz1PXPX8x06fj+XWgBDn3/P1P8AnHXjIoAOeRz25z/9bvxnPqT9QA7g5PUjrx3P+fT8KADkfn1J56/5789OtAH+hn/wY7/8k3/4KL/9jr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8UX/AILS/wDKWn/gozxn/jMj4+9s/wDM+ap+fNAH5jEdeP8Ax0H+76/j+vpQAgHPT1/g/L3/AK9jQAd+hxx/APxoAO7cHv8AwD1/X/JoACOenf8AuZH59f8APFACkdePX+EH+L/D9OaAE7Hj0/gH4/8A1/060ALjnoOp/g7c9+n4/ie9ABj2/wDHPf8AT8e3PWgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M3+fegD+7+gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/xRf+C0v/KWn/goz/2eR8fffr481X/P55oA/Mc85P8AMH1HXuenP/6qAGjqOB1bnB75xn2Pbnp34NAC4Oc46Y7ZPAHTk/j+mTQAYPXA5z29wfm75/Dr3oAMHrhfXpz/ACz75657UABHt+nqwPPf/HnPNAAAeRgdeuODj/PPpk0AHcH/AGj2OepOeme/596ADHTgdR7H72eOvGPf1zQB/oaf8GO//JN/+Ci//Y6/syf+o38ZqAP7v6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAMzWda0jw7pOp69r+qadomiaLp97q+saxq99a6ZpWk6VptvJeajqep6jfTQWWn6fY2sUtzeX15PDa2sEbzTyxxqWAB+H/AMUv+DlH/giz8JfE194T139trwp4k1bTbmW0vp/hl4A+LfxT8PRzRMysLXxf4D8C654U1WLKnFxo+s6hbE8CY9wDzP8A4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAP8xH/AIKa/Gj4d/tF/wDBQn9s747/AAi1yTxN8MPi7+0n8XPiF4B8QTaVquhzaz4U8U+LL/VNE1J9H12007WdNa7sp45WstTsbS+t9xjubeGUFFAPho55+uc8e3v25/TnPUATJz27+mef+Bfn/XrQADIPYZx6c8fX/H+VAC5OfpnnjPb/AGvz6dqADJz/APqzj/vr8KAA5/rzj1Hv6fTmgBMnnp79P1+b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ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAf4ov8AwWk/5Sz/APBRrP8A0eT8f/8A1PdU/pn/ABoA/MY9fTnv/wAB75Pt/XvkATg9x/F+H6jr3yfpgcgAUfUdvqcYOP5YwfqTzQAHHJyffkZHPTOfU/8A1+xADj15znqM56Z69fXtj+HNAB+P5/73+POcYzjoOKADjnnuOhHp9evHHOOmckGgA79ecn69W/n3yMcn2AAAY459OMjHX6k/r168cUAf6Gn/AAY7/wDJN/8Agov/ANjr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LSf8pZ/+CjX/AGeT8f8A/wBT3VKAPzFJ5J9+/wBU70AGQe3Zsc+uc8Y/LP60AGf129+eAPbn8+DycA0AGeSe+PUdMj2wP1Pr2oAM8/8AAj375+np+GOPvUABP9T1/wBv/PJ/xoAM8Hp1Hf29+e3f8ehoAUfeHrk/zb/PX0oAQHgDscdSP73p1NAH+hr/AMGO/wDyTf8A4KL/APY6/syf+o38Zs0Af3f0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH+KL/wWj/5S0f8FGucf8Zk/H/r/wBj7qn/AOv9fqAfmOfbHXp+K+3uT+INADefUfxenb8PXk9c9aAF5yeR2z05yB7c5/Cg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BQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH/2Q==", - "attach_logo": "logo-2013-color-small.png,data:image/png;base64,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", - "attach_profile": "rushabh.jpeg,data:image/jpeg;base64,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", - "company_abbr": "WN", - "company_name": "Web Notes", - "company_tagline": "Open Source ERP", - "country": "India", - "currency": "INR", - "customer_1": "RIGPL", - "customer_2": "Mahesh Engg", - "customer_contact_1": "Aditya Duggal", - "customer_contact_2": "Mahesh Malani", - "first_name": "Rushabh", - "fy_start": "1st Apr", - "item_1": "Enterprise", - "item_2": "Small Business", - "item_3": "Solo", - "item_buy_1": "Adwords", - "item_buy_2": "Server Hosting", - "item_img_1": "logo-2013-color-small.png,data:image/png;base64,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", - "last_name": "Mehta", - "tax_1": "Service Tax", - "tax_rate_1": "12.5", - "timezone": "Asia/Calcutta" +"attach_letterhead": "erpnext.jpg,data:image/jpeg;base64,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WVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBGZVBZmCgAsxYgAKvLMSeAAOSTwO9AHxV4x/4KU/8E6Ph5rl74Y+IH7ff7FPgbxLps8ttqPh7xj+1R8C/DOuWFzA2ya3vdJ1rx3ZX9rPC/ySxT28ckbHa6g8UAcv/wAPYf8Agln/ANJK/wBgH/xMj9nX8f8Amo1ACf8AD2H/AIJZf9JLP2AP/EyP2de//dRu+f1oAX/h7D/wSz/6SV/sA/8AiZH7Ov8A88agA/4ew/8ABLP/AKSV/sA/+Jkfs7f/ADxqAD/h7D/wSz7/APBSv9gH/wATI/Z1/wDnjUAH/D2H/gln/wBJK/2AeOv/ABmR+zrx/wCZGoAP+HsP/BLP/pJX+wD/AOJkfs6//PGoA+hvg1+1N+zH+0al7J+z3+0b8B/jummxLcai/wAGvi98PviglhA7KqTXreCPEOuC1idnVVknKIzMoDEsMgHvHXmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAQkKCx6AEn6Dk0Af5wP/B1n/wAFovjN4n/aI8a/8E0v2evHOs+APgv8I7LRtO/aI1jwfqt7pGs/GL4ka/olh4ivPAmra1YPbXx+HHgDSdW03StS8L2s9taeI/Gs2vt4ni1Wz0LQIbUA/iMbnOV/75VRnkf3QM/U89SeaAGjrnB6senXI/yPegAHB6HkL+HH+c/jQApJOcqeAR9ckd/8+tAC55xg9euPf/Jz/wDroARuexPH/sw4/HH5c80AGfvHDc+31/yT7/mAL3A56k5xx/F/n/8AXQB6F8Kfi18TfgZ4/wDDHxU+Dvjvxb8MviN4N1ODV/C/jbwNruoeGfE+h39vIHjnsNY0qa3uowwXy7i3leW0u4Ge2vLe4tpZYmAP9ef/AIN/v+CpWs/8FUP2FdM+JXxLTS7b9oX4P+Kp/g98dl0i1i03T/EviPTdG0zW/DvxM03R7eNLXSbP4heG9St77UdPsUt9MsvGGm+LLPRrKz0a3sLaIA/cmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBCMgg9Dwfcd/wA6AP8AFM/4LVzzXH/BWv8A4KLvPI8rr+2J8d4VZzkiK28a6hbW8YP92GCGKJB/CiKO1AH5gc4P178Dkr1B555+vP8AeoAQZz/30Oo3Hjue+P0oAXn+R65PQc8fr/eHSgA556dPoOvcdc46n8KADnrjv3Pqf5eg659aAA5//Wf9rv6jB/DJHegBOfm6Z4789O/9emRmgBecj6nvx1bt6/5NABzx069zk/e556env2oA/wBDj/gx5mmf4Yf8FErdpGMEPjv9mqeKInKRzT+GPi/FPIo7PLHbQI57rEg/hoA/u7oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LS/8paf+CjPr/wANkfH3/wBTvVPf/wDX60AfmMc4Of8A638PU8H1/wA4oAQZyPXLc8dcc9+oP4GgAGc47kLnt0A98nvnj/64ApyScjsR147d+OvvjjmgAyc49we3r9c/Q9c8HrQAN7+/6sMDr7df60AHPzevGenp356EfzPXFABzkdcZPp1+b3z/AJ9aADnAHvknj+96e/8AkmgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M1AH939ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/ijf8ABaX/AJS0/wDBRn/s8j4+8/8Ac+ap3/zzQB+Y3+Prx1Ht/TqT60AIM+p/i53c+nPH5dcGgBec9+MdT+PoefXnoe+RQAvPX29ePr06/gaADBz1PXPX8x06fj+XWgBDn3/P1P8AnHXjIoAOeRz25z/9bvxnPqT9QA7g5PUjrx3P+fT8KADkfn1J56/5789OtAH+hn/wY7/8k3/4KL/9jr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8UX/AILS/wDKWn/gozxn/jMj4+9s/wDM+ap+fNAH5jEdeP8Ax0H+76/j+vpQAgHPT1/g/L3/AK9jQAd+hxx/APxoAO7cHv8AwD1/X/JoACOenf8AuZH59f8APFACkdePX+EH+L/D9OaAE7Hj0/gH4/8A1/060ALjnoOp/g7c9+n4/ie9ABj2/wDHPf8AT8e3PWgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M3+fegD+7+gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/xRf+C0v/KWn/goz/2eR8fffr481X/P55oA/Mc85P8AMH1HXuenP/6qAGjqOB1bnB75xn2Pbnp34NAC4Oc46Y7ZPAHTk/j+mTQAYPXA5z29wfm75/Dr3oAMHrhfXpz/ACz75657UABHt+nqwPPf/HnPNAAAeRgdeuODj/PPpk0AHcH/AGj2OepOeme/596ADHTgdR7H72eOvGPf1zQB/oaf8GO//JN/+Ci//Y6/syf+o38ZqAP7v6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAMzWda0jw7pOp69r+qadomiaLp97q+saxq99a6ZpWk6VptvJeajqep6jfTQWWn6fY2sUtzeX15PDa2sEbzTyxxqWAB+H/AMUv+DlH/giz8JfE194T139trwp4k1bTbmW0vp/hl4A+LfxT8PRzRMysLXxf4D8C654U1WLKnFxo+s6hbE8CY9wDzP8A4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAP8xH/AIKa/Gj4d/tF/wDBQn9s747/AAi1yTxN8MPi7+0n8XPiF4B8QTaVquhzaz4U8U+LL/VNE1J9H12007WdNa7sp45WstTsbS+t9xjubeGUFFAPho55+uc8e3v25/TnPUATJz27+mef+Bfn/XrQADIPYZx6c8fX/H+VAC5OfpnnjPb/AGvz6dqADJz/APqzj/vr8KAA5/rzj1Hv6fTmgBMnnp79P1+b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ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAf4ov8AwWk/5Sz/APBRrP8A0eT8f/8A1PdU/pn/ABoA/MY9fTnv/wAB75Pt/XvkATg9x/F+H6jr3yfpgcgAUfUdvqcYOP5YwfqTzQAHHJyffkZHPTOfU/8A1+xADj15znqM56Z69fXtj+HNAB+P5/73+POcYzjoOKADjnnuOhHp9evHHOOmckGgA79ecn69W/n3yMcn2AAAY459OMjHX6k/r168cUAf6Gn/AAY7/wDJN/8Agov/ANjr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LSf8pZ/+CjX/AGeT8f8A/wBT3VKAPzFJ5J9+/wBU70AGQe3Zsc+uc8Y/LP60AGf129+eAPbn8+DycA0AGeSe+PUdMj2wP1Pr2oAM8/8AAj375+np+GOPvUABP9T1/wBv/PJ/xoAM8Hp1Hf29+e3f8ehoAUfeHrk/zb/PX0oAQHgDscdSP73p1NAH+hr/AMGO/wDyTf8A4KL/APY6/syf+o38Zs0Af3f0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH+KL/wWj/5S0f8FGucf8Zk/H/r/wBj7qn/AOv9fqAfmOfbHXp+K+3uT+INADefUfxenb8PXk9c9aAF5yeR2z05yB7c5/CgBeeeRj6j1+n4d+aADnPUYz6j8unX8f8AGgAOfUfp/e+nbpnnmgBMnnkZyOcj0+nft/8AW5AF5yPqf/Zuen659etACc8HIPTPQ9W+n9RyPagD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M1AH939ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/ii/8ABaT/AJSz/wDBRr/s8j4//wDqe6pQB+Yx9D0z9B1Tt+P86ADPvzh/55/+vQAA+uCTjr7qO3Xn2/HHWgBCcgjjvnkdcjnOePofpQAuQfrn27N09f8AH6mgBD156d8+z/8A16AAkHP1/mp/qf1J9aAFB5x7k/q9ACA56nk7fTsx7UAf6Gv/AAY7/wDJN/8Agov/ANjr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAa2drbeWwSo9Tjj9aAP8bP/g4Y+B3jL4Ef8FhP23tK8XaZcWdv8R/i5qfxz8H6jIjiy8QeDPjNbW/jXS9U0q4Py3dtZ6hfax4bvpYiyW+uaBq+nE+fZyKAD8WSc56fjn/Z64P8vb/aoATjPbv/AHvQ+v69/TmgA4yDx2/vdgPw+mT9aADj5unP+96jr/8AWzz7ZoAON3bOf9rPX8s/pQAp79Oh65/vd8H1/HPtzQAnGD93qP73v+P+TntQA7+IHHr655J98eucn1x2oAb6dP8Ax7+91H/1+/4UAf6UP/BlL8DvGfgz9kD9rD4767plzpvhb43/ABu8HeFPA812jRHXbL4K+FNYtvEOu6crAC50hfEfj+58OpfRFon1fw/rViT5thKoAP7VKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgD8dP+Cuv/AARY/Zj/AOCu3w40LSvifd6l8MPjf8PbW/t/hP8AtA+ENMsdS8S+GrLUpRdX3hLxXod7LZ2nj74e3t8F1NvDV9qOl6hpGq+fqPhbxD4fn1PXBqoB/F34x/4Mof8AgovZ67eweAP2m/2KPEvhpJpV0/VvF/iP47eB9durcOPJlvPD2j/BD4i2FhPIg3SwQeJ9Rjhb5UuZx89AHLf8QVf/AAVMz/yXz9gHnOc/FP8AaKPU5/6NW79/8mgA/wCIKv8A4KmZ/wCS+fsA9R/zVP8AaJ/X/jFbt29OvWgA/wCIKv8A4Kmc/wDF/f2Avr/wtP8AaJz9M/8ADK3T2/WgA/4gq/8AgqZ/0Xz9gH8Pil+0T+f/ACat19T3HGKAA/8ABlX/AMFTP+i+fsA/+HT/AGifXP8A0at17n1PoKAD/iCr/wCCpnP/ABf39gLr/wBFT/aJ/wDoVu3bnjjrigA/4gq/+Cpn/RfP2AepOf8Ahaf7ROe//Vqvv+poA+y/2Q/+DKD4oRePNG1r9uf9qz4aQ/DzSr22vNW8Dfsw2/jHxD4k8X28UqPNo6/EL4meEfAtt4MguFDRy6raeBfE995RZLWKxuHS9twD+974LfBj4X/s7/CnwF8EPgr4K0T4d/Cv4Y+G9P8ACXgfwZ4egeHS9C0PTUKwwI80k15fXt1M82oavrOp3N5rGu6vd32s6zfX2qX13dTAHp9ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH/2Q==", +"attach_logo": "logo-2013-color-small.png,data:image/png;base64,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", +"attach_profile": "rushabh.jpeg,data:image/jpeg;base64,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", +"company_abbr": "WN", +"company_name": "Web Notes", +"company_tagline": "Open Source ERP", +"country": "India", +"currency": "INR", +"customer_1": "RIGPL", +"customer_2": "Mahesh Engg", +"customer_contact_1": "Aditya Duggal", +"customer_contact_2": "Mahesh Malani", +"first_name": "Rushabh", +"fy_start": "1st Apr", +"item_1": "Enterprise Plan", +"item_2": "Small Business", +"item_3": "Solo", +"item_4": "Manual", +"item_buy_1": "Server Hosting", +"item_buy_2": "Adwords", +"item_buy_group_1": "Services", +"item_buy_group_2": "Services", +"item_buy_group_3": "Raw Material", +"item_buy_group_4": "Raw Material", +"item_buy_group_5": "Raw Material", +"item_buy_uom_1": "Unit", +"item_buy_uom_2": "Unit", +"item_buy_uom_3": "Unit", +"item_buy_uom_4": "Unit", +"item_buy_uom_5": "Unit", +"item_group_1": "Services", +"item_group_2": "Services", +"item_group_3": "Services", +"item_group_4": "Products", +"item_group_5": "Products", +"item_img_1": "logo-2013-color-small.png,data:image/png;base64,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", +"item_uom_1": "Unit", +"item_uom_2": "Unit", +"item_uom_3": "Unit", +"item_uom_4": "Unit", +"item_uom_5": "Unit", +"last_name": "Mehta", +"supplier_1": "Google", +"supplier_2": "Hetzner", +"supplier_3": "Digital Ocean", +"tax_1": "Service Tax", +"tax_rate_1": "12.5", +"timezone": "Asia/Calcutta", +"password": "password", +"email": "test@erpnext.com", } \ No newline at end of file diff --git a/startup/install.py b/startup/install.py index 59b74965b9..fd7221380d 100644 --- a/startup/install.py +++ b/startup/install.py @@ -71,6 +71,7 @@ def import_defaults(): {'doctype': 'Item Group', 'item_group_name': 'Raw Material', 'is_group': 'No', 'parent_item_group': 'All Item Groups'}, {'doctype': 'Item Group', 'item_group_name': 'Services', 'is_group': 'No', 'parent_item_group': 'All Item Groups'}, {'doctype': 'Item Group', 'item_group_name': 'Sub Assemblies', 'is_group': 'No', 'parent_item_group': 'All Item Groups'}, + {'doctype': 'Item Group', 'item_group_name': 'Consumable', 'is_group': 'No', 'parent_item_group': 'All Item Groups'}, # deduction type {'doctype': 'Deduction Type', 'name': 'Income Tax', 'description': 'Income Tax', 'deduction_name': 'Income Tax'}, diff --git a/support/doctype/support_ticket/get_support_mails.py b/support/doctype/support_ticket/get_support_mails.py index 4b61352fae..395052aa27 100644 --- a/support/doctype/support_ticket/get_support_mails.py +++ b/support/doctype/support_ticket/get_support_mails.py @@ -81,7 +81,7 @@ def add_support_communication(subject, content, sender, docname=None, mail=None) make(content=content, sender=sender, subject = subject, doctype="Support Ticket", name=ticket.doc.name, - date=mail.date if mail else today()) + date=mail.date if mail else today(), sent_or_received="Received") if mail: mail.save_attachments_in_doc(ticket.doc) From 30bd908833252c65eb3f831998fae04559c671b2 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 9 Oct 2013 17:37:41 +0530 Subject: [PATCH 093/123] [fix] [minor] setup leave approver select option in employee --- hr/doctype/employee/employee.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js index 01200e7d22..615e2761b8 100644 --- a/hr/doctype/employee/employee.js +++ b/hr/doctype/employee/employee.js @@ -4,7 +4,6 @@ wn.provide("erpnext.hr"); erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ setup: function() { - this.setup_leave_approver_select(); this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) { return { query:"core.doctype.profile.profile.profile_query"} } this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) { @@ -12,6 +11,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ }, onload: function() { + this.setup_leave_approver_select(); this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"], wn.control_panel.country==="India"); if(this.frm.doc.__islocal) this.frm.set_value("employee_name", ""); From 7798934989493a269070785283de1e22f4ba1baf Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 10 Oct 2013 12:03:11 +0530 Subject: [PATCH 094/123] [minor] fixed globals and patch for wsgi migration --- .../p06_fix_sle_against_stock_entry.py | 18 +++++------ patches/october_2013/p04_wsgi_migration.py | 30 +++++++++++++++++++ patches/patch_list.py | 1 + utilities/demo/make_demo.py | 2 +- utilities/demo/make_erpnext_demo.py | 2 +- 5 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 patches/october_2013/p04_wsgi_migration.py diff --git a/patches/august_2013/p06_fix_sle_against_stock_entry.py b/patches/august_2013/p06_fix_sle_against_stock_entry.py index 02588bec6d..2e6c383ebd 100644 --- a/patches/august_2013/p06_fix_sle_against_stock_entry.py +++ b/patches/august_2013/p06_fix_sle_against_stock_entry.py @@ -1,10 +1,9 @@ import webnotes -cancelled = [] -uncancelled = [] - def execute(): - global cancelled, uncancelled + cancelled = [] + uncancelled = [] + stock_entries = webnotes.conn.sql("""select * from `tabStock Entry` where docstatus >= 1 and date(modified) >= "2013-08-16" and ifnull(production_order, '') != '' and ifnull(bom_no, '') != '' @@ -17,14 +16,12 @@ def execute(): where voucher_type='Stock Entry' and voucher_no=%s and is_cancelled='No'""", entry.name, as_dict=True) if res: - make_stock_entry_detail(entry, res) + make_stock_entry_detail(entry, res, cancelled, uncancelled) if cancelled or uncancelled: - send_email() + send_email(cancelled, uncancelled) -def make_stock_entry_detail(entry, res): - global cancelled, uncancelled - +def make_stock_entry_detail(entry, res, cancelled, uncancelled): fg_item = webnotes.conn.get_value("Production Order", entry.production_order, "production_item") voucher_detail_entries_map = {} @@ -87,9 +84,8 @@ def make_stock_entry_detail(entry, res): uncancelled.append(se.doc.name) -def send_email(): +def send_email(cancelled, uncancelled): from webnotes.utils.email_lib import sendmail_to_system_managers - global cancelled, uncancelled uncancelled = "we have undone the cancellation of the following Stock Entries through a patch:\n" + \ "\n".join(uncancelled) if uncancelled else "" cancelled = "and cancelled the following Stock Entries:\n" + "\n".join(cancelled) \ diff --git a/patches/october_2013/p04_wsgi_migration.py b/patches/october_2013/p04_wsgi_migration.py new file mode 100644 index 0000000000..ca73516c25 --- /dev/null +++ b/patches/october_2013/p04_wsgi_migration.py @@ -0,0 +1,30 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +import webnotes.utils +import os + +def execute(): + base_path = webnotes.utils.get_base_path() + + # Remove symlinks from public folder: + # - server.py + # - web.py + # - unsupported.html + # - blank.html + # - rss.xml + # - sitemap.xml + for file in ("server.py", "web.py", "unsupported.html", "blank.html", "rss.xml", "sitemap.xml"): + file_path = os.path.join(base_path, "public", file) + if os.path.exists(file_path): + os.remove(file_path) + + # Remove wn-web files + # - js/wn-web.js + # - css/wn-web.css + for file_path in (("js", "wn-web.js"), ("css", "wn-web.css")): + file_path = os.path.join(base_path, "public", *file_path) + if os.path.exists(file_path): + os.remove(file_path) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index a5693854e5..92dd52742c 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -224,4 +224,5 @@ patch_list = [ "patches.october_2013.p02_set_communication_status", "patches.october_2013.p03_crm_update_status", "execute:webnotes.delete_doc('DocType', 'Setup Control')", + "patches.october_2013.p04_wsgi_migration", ] \ No newline at end of file diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index d335528dfc..219ce86496 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -75,7 +75,7 @@ def _simulate(): for i in xrange(runs_for): print current_date.strftime("%Y-%m-%d") - webnotes.utils.current_date = current_date + webnotes.local.current_date = current_date if current_date.weekday() in (5, 6): current_date = webnotes.utils.add_days(current_date, 1) diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index d67fb5ece0..bc25d5e34d 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -6,8 +6,8 @@ import webnotes, os import utilities.demo.make_demo def make_demo_app(site=None): - webnotes.flags.mute_emails = 1 webnotes.init(site=site) + webnotes.flags.mute_emails = 1 utilities.demo.make_demo.make(reset=True, simulate=False) # setup demo user etc so that the site it up faster, while the data loads From 51f4ac15925107b678982d88f7b8dcf9469a94e8 Mon Sep 17 00:00:00 2001 From: Priya Date: Thu, 10 Oct 2013 12:44:31 +0530 Subject: [PATCH 095/123] [docs] minor image changes --- .../five_day_setup/docs.user.five_day_setup.day_1.md | 10 +++++----- .../five_day_setup/docs.user.five_day_setup.day_2.md | 10 +++++----- .../five_day_setup/docs.user.five_day_setup.day_3.md | 12 ++++++------ .../five_day_setup/docs.user.five_day_setup.day_4.md | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index 34f85dd911..a64f833bd7 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -9,7 +9,7 @@ After logging into your account you will receive a pop-up form to fill. Please f #### Form Part I -![1st Form](img/firstdaysetup_1.png) +![1st Form](img/firstdaysetup-1.png)
#### Form Part II
@@ -17,7 +17,7 @@ After logging into your account you will receive a pop-up form to fill. Please f To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) -![1st Form](img/firstdaysetup_2.png) +![1st Form](img/firstdaysetup-2.png) After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear. @@ -55,7 +55,7 @@ Create a new Item. An Item is your company's product or a service.The term Item Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item. -![Item](img/firstdaysetup_item_1.png) +![Item](img/firstdaysetup-item-1.png) To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers. @@ -65,12 +65,12 @@ To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.h On the Setup page go to Supplier. -![Supplier](img/firstdaysetup_supplier.png) +![Supplier](img/firstdaysetup-supplier.png)
Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record. -![Supplier](img/firstdaysetup_supplier_1.png) +![Supplier](img/firstdaysetup-supplier-1.png) To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html). diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index c1a5d28cb7..11e13e2ea9 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -8,14 +8,14 @@ Go to the Accounts icon and make ledgers under Chart of Accounts. -![Accounts](img/seconddaysetup_accounts.png) +![Accounts](img/seconddaysetup-accounts.png)
Create acccounting ledgers. -![Tree](img/seconddaysetup_tree.png) +![Tree](img/seconddaysetup-tree.png)
@@ -23,7 +23,7 @@ To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page.
-![Ledger](img/seconddaysetup_accounts_jv.png) +![Ledger](img/seconddaysetup-accounts-jv.png)
@@ -34,7 +34,7 @@ To understand how to create opening entries in detail visit [Opening Entry](docs You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. -![Stock Opening](img/seconddaysetup_stock_opening.png) +![Stock Opening](img/seconddaysetup-stock-opening.png)
@@ -46,7 +46,7 @@ To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.o To setup HR, begin by creating individual employee records. -![Employee](img/seconddaysetup_hr.png) +![Employee](img/seconddaysetup-hr.png) To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index dc7acef0fd..a916837227 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -26,13 +26,13 @@ After completing the Lead form, assume that, this same lead is getting converted ##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status. -![Opportunity](img/thirddaysetup_opportunity_1.png) +![Opportunity](img/thirddaysetup-opportunity-1.png)
##### Step 2: Generate Opportunity from the selected Lead -![Opportunity](img/thirddaysetup_opportunity.png) +![Opportunity](img/thirddaysetup-opportunity.png) You can also generate an Opportunity directly from the Selling Page. @@ -43,7 +43,7 @@ You can also generate an Opportunity directly from the Selling Page. Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. -![Quotation](img/thirddaysetup_quotation.png) +![Quotation](img/thirddaysetup-quotation.png) You can also generate a Quotation directly from the Selling Page. @@ -54,7 +54,7 @@ You can also generate a Quotation directly from the Selling Page. Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. -![Sales Order](img/thirddaysetup_sales_order.png) +![Sales Order](img/thirddaysetup-sales-order.png) You can also generate a Sales Order directly from the Selling Page. @@ -65,7 +65,7 @@ You can also generate a Sales Order directly from the Selling Page. If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. -![Delivery Note](img/thirddaysetup_delivery_note.png) +![Delivery Note](img/thirddaysetup-delivery-note.png) > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) @@ -74,7 +74,7 @@ If your organisation has the practice of sending Delivery Note, this section wil Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. -![Sales Invoice](img/thirddaysetup_sales_invoice.png) +![Sales Invoice](img/thirddaysetup-sales-invoice.png)
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index f4938e9c07..c93a63212d 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -12,7 +12,7 @@ Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. -![Bill of Materials](img/fourthdaysetup_bom.png) +![Bill of Materials](img/fourthdaysetup-bom.png)
@@ -22,7 +22,7 @@ To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, c To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. -![Production Planning Page](img/fourthdaysetup_ppt.png) +![Production Planning Page](img/fourthdaysetup-ppt.png)
@@ -57,7 +57,7 @@ To go to Stock Entry, click on the Stock Icon and go to Stock Entry. To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. -[Delivery Note](img/fourthdaysetup_delivery_note.png) +![Delivery Note](img/fourthdaysetup-delivery-note.png)
From 69ad94a795c29e11e1ccce7b7712c247243e373b Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Oct 2013 15:30:12 +0530 Subject: [PATCH 096/123] [minor] fixes to form layouts --- setup/doctype/uom/uom.txt | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/setup/doctype/uom/uom.txt b/setup/doctype/uom/uom.txt index 6577f6c005..51d9806755 100644 --- a/setup/doctype/uom/uom.txt +++ b/setup/doctype/uom/uom.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-10 16:34:24", "docstatus": 0, - "modified": "2013-07-25 16:18:17", + "modified": "2013-10-10 15:06:53", "modified_by": "Administrator", "owner": "Administrator" }, @@ -38,22 +38,6 @@ "doctype": "DocType", "name": "UOM" }, - { - "doctype": "DocField", - "fieldname": "trash_reason", - "fieldtype": "Small Text", - "label": "Trash Reason", - "oldfieldname": "trash_reason", - "oldfieldtype": "Small Text", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "uom_details", - "fieldtype": "Section Break", - "label": "UOM Details", - "oldfieldtype": "Section Break" - }, { "doctype": "DocField", "fieldname": "uom_name", From b604eddbfd47eea2404e4e20e25ac9665fba7fd7 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 10 Oct 2013 15:43:32 +0530 Subject: [PATCH 097/123] [minor] [fixes] view in website and other fixes --- selling/doctype/sales_order/sales_order.py | 2 +- setup/doctype/item_group/item_group.js | 6 ++++++ setup/page/setup_wizard/setup_wizard.py | 5 ++--- stock/doctype/item/item.js | 16 +++++++++------- stock/doctype/item/item.py | 3 +++ stock/doctype/serial_no/serial_no.py | 4 ++-- utilities/demo/make_erpnext_demo.py | 1 + 7 files changed, 24 insertions(+), 13 deletions(-) diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index d3ac7ad339..af8ea1ad7a 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -202,7 +202,7 @@ class DocType(SellingController): def check_nextdoc_docstatus(self): # Checks Delivery Note - submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) + submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.doc.name) if submit_dn: msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) diff --git a/setup/doctype/item_group/item_group.js b/setup/doctype/item_group/item_group.js index 31edef27de..0c18db001c 100644 --- a/setup/doctype/item_group/item_group.js +++ b/setup/doctype/item_group/item_group.js @@ -7,6 +7,12 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { cur_frm.add_custom_button("Item Group Tree", function() { wn.set_route("Sales Browser", "Item Group"); }) + + if(!doc.__islocal && doc.show_in_website) { + cur_frm.add_custom_button("View In Website", function() { + window.open(doc.page_name); + }, "icon-globe"); + } } cur_frm.cscript.set_root_readonly = function(doc) { diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py index 12767639c8..d506d41954 100644 --- a/setup/page/setup_wizard/setup_wizard.py +++ b/setup/page/setup_wizard/setup_wizard.py @@ -17,9 +17,8 @@ def setup_account(args=None): args = webnotes.local.form_dict if isinstance(args, basestring): args = json.loads(args) - - webnotes.conn.begin() - + args = webnotes._dict(args) + update_profile_name(args) create_fiscal_year_and_company(args) set_defaults(args) diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js index a83032e8f2..d0b8492ddd 100644 --- a/stock/doctype/item/item.js +++ b/stock/doctype/item/item.js @@ -11,14 +11,16 @@ cur_frm.cscript.refresh = function(doc) { && doc.__islocal) cur_frm.toggle_display("item_code", sys_defaults.item_naming_by!="Naming Series" && doc.__islocal) + + if(!doc.__islocal && doc.show_in_website) { + cur_frm.add_custom_button("View In Website", function() { + window.open(doc.page_name); + }, "icon-globe"); + } - - if ((!doc.__islocal) && (doc.is_stock_item == 'Yes')) { - var callback = function(r, rt) { - var enabled = (r.message == 'exists') ? false : true; - cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'], enabled); - } - return $c_obj(make_doclist(doc.doctype, doc.name),'check_if_sle_exists','',callback); + if (!doc.__islocal && doc.is_stock_item == 'Yes') { + cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'], + doc.__sle_exists=="exists" ? false : true); } } diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py index aedb71c2c2..595895f61a 100644 --- a/stock/doctype/item/item.py +++ b/stock/doctype/item/item.py @@ -14,6 +14,9 @@ from webnotes.model.controller import DocListController class WarehouseNotSet(Exception): pass class DocType(DocListController): + def onload(self): + self.doc.fields["__sle_exists"] = self.check_if_sle_exists() + def autoname(self): if webnotes.conn.get_default("item_naming_by")=="Naming Series": from webnotes.model.doc import make_autoname diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 1feab02cf5..3b9704fcd5 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -14,9 +14,9 @@ class SerialNoCannotCreateDirectError(webnotes.ValidationError): pass class SerialNoCannotCannotChangeError(webnotes.ValidationError): pass class DocType(StockController): - def __init__(self, doc, doclist=[]): + def __init__(self, doc, doclist=None): self.doc = doc - self.doclist = doclist + self.doclist = doclist or [] self.via_stock_ledger = False def validate(self): diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index bc25d5e34d..262a7595c2 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -15,6 +15,7 @@ def make_demo_app(site=None): make_demo_login_page() make_demo_on_login_script() utilities.demo.make_demo.make(reset=False, simulate=True) + webnotes.destroy() def make_demo_user(): from webnotes.auth import _update_password From 373680bbae0895a9af1d6500c63d224cc3347b5a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 10 Oct 2013 16:04:40 +0530 Subject: [PATCH 098/123] Merged master into wsgi --- accounts/doctype/gl_entry/gl_entry.py | 2 +- .../purchase_invoice/purchase_invoice.py | 31 ++- .../doctype/sales_invoice/sales_invoice.py | 2 - .../doctype/sales_invoice/sales_invoice.txt | 3 +- .../item_wise_purchase_register.py | 4 +- .../item_wise_sales_register.py | 14 +- buying/page/buying_home/buying_home.js | 5 + .../__init__.py | 0 .../supplier_addresses_and_contacts.txt | 22 ++ controllers/buying_controller.py | 19 +- controllers/selling_controller.py | 32 +-- hr/doctype/employee/employee.js | 2 +- .../production_order/production_order.py | 29 ++- .../october_2013/p01_fix_serial_no_status.py | 18 ++ ...petual_inventory_stock_transfer_utility.py | 86 +++++++ .../set_stock_value_diff_in_sle.py | 10 + selling/doctype/lead/lead.py | 2 +- selling/doctype/lead/lead.txt | 116 ++++----- selling/doctype/opportunity/opportunity.py | 17 +- selling/doctype/opportunity/opportunity.txt | 16 +- selling/doctype/quotation/quotation.py | 17 +- selling/doctype/sales_order/sales_order.py | 7 +- selling/utils/__init__.py | 2 +- stock/doctype/delivery_note/delivery_note.py | 31 --- .../landed_cost_wizard/landed_cost_wizard.py | 4 +- .../material_request/material_request.py | 12 +- .../purchase_receipt/purchase_receipt.py | 21 +- stock/doctype/serial_no/serial_no.py | 225 ++++++++++++++++-- stock/doctype/stock_entry/stock_entry.py | 24 +- stock/doctype/stock_entry/test_stock_entry.py | 16 +- .../stock_ledger_entry/stock_ledger_entry.py | 138 +---------- stock/utils.py | 7 + .../maintenance_schedules.txt | 4 +- 33 files changed, 520 insertions(+), 418 deletions(-) create mode 100644 buying/report/supplier_addresses_and_contacts/__init__.py create mode 100644 buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt create mode 100644 patches/october_2013/p01_fix_serial_no_status.py create mode 100644 patches/october_2013/perpetual_inventory_stock_transfer_utility.py create mode 100644 patches/october_2013/set_stock_value_diff_in_sle.py diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py index 22435120e0..7a73b06756 100644 --- a/accounts/doctype/gl_entry/gl_entry.py +++ b/accounts/doctype/gl_entry/gl_entry.py @@ -107,7 +107,7 @@ class DocType: _(" does not belong to the company") + ": " + self.doc.company) def check_negative_balance(account, adv_adj=False): - if not adv_adj: + if not adv_adj and account: account_details = webnotes.conn.get_value("Account", account, ["allow_negative_balance", "debit_or_credit"], as_dict=True) if not account_details["allow_negative_balance"]: diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 46faf3df59..c79bfd6648 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -337,7 +337,7 @@ class DocType(BuyingController): ) # tax table gl entries - valuation_tax = 0 + valuation_tax = {} for tax in self.doclist.get({"parentfield": "purchase_tax_details"}): if tax.category in ("Total", "Valuation and Total") and flt(tax.tax_amount): gl_entries.append( @@ -352,8 +352,11 @@ class DocType(BuyingController): ) # accumulate valuation tax - if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount): - valuation_tax += (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) + if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount) \ + and tax.cost_center: + valuation_tax.setdefault(tax.cost_center, 0) + valuation_tax[tax.cost_center] += \ + (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) # item gl entries stock_item_and_auto_accounting_for_stock = False @@ -394,15 +397,19 @@ class DocType(BuyingController): if stock_item_and_auto_accounting_for_stock and valuation_tax: # credit valuation tax amount in "Expenses Included In Valuation" # this will balance out valuation amount included in cost of goods sold - gl_entries.append( - self.get_gl_dict({ - "account": self.get_company_default("expenses_included_in_valuation"), - "cost_center": self.get_company_default("cost_center"), - "against": self.doc.credit_to, - "credit": valuation_tax, - "remarks": self.doc.remarks or "Accounting Entry for Stock" - }) - ) + expenses_included_in_valuation = \ + self.get_company_default("expenses_included_in_valuation") + + for cost_center, amount in valuation_tax.items(): + gl_entries.append( + self.get_gl_dict({ + "account": expenses_included_in_valuation, + "cost_center": cost_center, + "against": self.doc.credit_to, + "credit": amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock" + }) + ) # writeoff account includes petty difference in the invoice amount # and the amount that is paid diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 1dca77b3fb..5c7597c403 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -83,7 +83,6 @@ class DocType(SellingController): def on_submit(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos() else: # Check for Approving Authority if not self.doc.recurring_id: @@ -111,7 +110,6 @@ class DocType(SellingController): def on_cancel(self): if cint(self.doc.update_stock) == 1: self.update_stock_ledger() - self.update_serial_nos(cancel = True) sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 77cf2ccef2..8cd83c4596 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-10-02 14:24:50", + "modified": "2013-10-03 18:54:31", "modified_by": "Administrator", "owner": "Administrator" }, @@ -181,7 +181,6 @@ "search_index": 1 }, { - "default": "Today", "description": "Enter the date by which payments from customer is expected against this invoice.", "doctype": "DocField", "fieldname": "due_date", diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index bd0726e37d..1c3cef3115 100644 --- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -81,12 +81,12 @@ def get_tax_accounts(item_list, columns): if account_head not in tax_accounts: tax_accounts.append(account_head) - invoice = item_tax.setdefault(parent, {}) if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 77fb6f25e6..48bc463f14 100644 --- a/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -9,7 +9,7 @@ def execute(filters=None): if not filters: filters = {} columns = get_columns() last_col = len(columns) - + item_list = get_items(filters) item_tax, tax_accounts = get_tax_accounts(item_list, columns) @@ -21,7 +21,7 @@ def execute(filters=None): for tax in tax_accounts: row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0)) - + total_tax = sum(row[last_col:]) row += [total_tax, d.amount + total_tax] @@ -71,19 +71,19 @@ def get_tax_accounts(item_list, columns): tax_details = webnotes.conn.sql("""select parent, account_head, item_wise_tax_detail from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' and docstatus = 1 and ifnull(account_head, '') != '' - and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list])) + and parent in (%s)""" % ', '.join(['%s']*len(item_list)), + tuple([item.parent for item in item_list])) for parent, account_head, item_wise_tax_detail in tax_details: if account_head not in tax_accounts: tax_accounts.append(account_head) - - invoice = item_tax.setdefault(parent, {}) + if item_wise_tax_detail: try: item_wise_tax_detail = json.loads(item_wise_tax_detail) for item, tax_amount in item_wise_tax_detail.items(): - invoice.setdefault(item, {})[account_head] = flt(tax_amount) - + item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \ + flt(tax_amount[1]) except ValueError: continue diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js index 5db57f4f02..eec0725de9 100644 --- a/buying/page/buying_home/buying_home.js +++ b/buying/page/buying_home/buying_home.js @@ -145,6 +145,11 @@ wn.module_page["Buying"] = [ route: "query-report/Purchase Order Trends", doctype: "Purchase Order" }, + { + "label":wn._("Supplier Addresses And Contacts"), + route: "query-report/Supplier Addresses and Contacts", + doctype: "Supplier" + }, ] } ] diff --git a/buying/report/supplier_addresses_and_contacts/__init__.py b/buying/report/supplier_addresses_and_contacts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt new file mode 100644 index 0000000000..fac1e9e929 --- /dev/null +++ b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt @@ -0,0 +1,22 @@ +[ + { + "creation": "2013-10-09 10:38:40", + "docstatus": 0, + "modified": "2013-10-09 10:53:52", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "Report", + "is_standard": "Yes", + "name": "__common__", + "query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc", + "ref_doctype": "Supplier", + "report_name": "Supplier Addresses and Contacts", + "report_type": "Query Report" + }, + { + "doctype": "Report", + "name": "Supplier Addresses and Contacts" + } +] \ No newline at end of file diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 7e49e60f8a..25d76aa66d 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -24,7 +24,7 @@ class BuyingController(StockController): self.doc.supplier_name = webnotes.conn.get_value("Supplier", self.doc.supplier, "supplier_name") self.validate_stock_or_nonstock_items() - self.validate_warehouse_belongs_to_company() + self.validate_warehouse() def set_missing_values(self, for_validate=False): super(BuyingController, self).set_missing_values(for_validate) @@ -49,17 +49,20 @@ class BuyingController(StockController): if supplier: self.doc.supplier = supplier break + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + warehouses = list(set([d.warehouse for d in + self.doclist.get({"doctype": self.tname}) if d.warehouse])) + + for w in warehouses: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def get_purchase_tax_details(self): self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details") self.set_taxes("purchase_tax_details", "purchase_other_charges") - - def validate_warehouse_belongs_to_company(self): - for warehouse, company in webnotes.conn.get_values("Warehouse", - self.doclist.get_distinct_values("warehouse"), "company").items(): - if company and company != self.doc.company: - webnotes.msgprint(_("Company mismatch for Warehouse") + (": %s" % (warehouse,)), - raise_exception=WrongWarehouseCompany) def validate_stock_or_nonstock_items(self): if not self.get_stock_items(): diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 2816524160..d78cf932b4 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -236,34 +236,4 @@ class SellingController(StockController): self.doc.order_type = "Sales" elif self.doc.order_type not in valid_types: msgprint(_(self.meta.get_label("order_type")) + " " + - _("must be one of") + ": " + comma_or(valid_types), - raise_exception=True) - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, self.doc.doctype, self.fname) - update_serial_nos_after_submit(self, self.doc.doctype, "packing_details") - - for table_fieldname in (self.fname, "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = self.doc.doctype - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() + _("must be one of") + ": " + comma_or(valid_types), raise_exception=True) diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js index 01200e7d22..615e2761b8 100644 --- a/hr/doctype/employee/employee.js +++ b/hr/doctype/employee/employee.js @@ -4,7 +4,6 @@ wn.provide("erpnext.hr"); erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ setup: function() { - this.setup_leave_approver_select(); this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) { return { query:"core.doctype.profile.profile.profile_query"} } this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) { @@ -12,6 +11,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ }, onload: function() { + this.setup_leave_approver_select(); this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"], wn.control_panel.country==="India"); if(this.frm.doc.__islocal) this.frm.set_value("employee_name", ""); diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index a280a82202..6bceca6da8 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -21,13 +21,14 @@ class DocType: utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "In Process", "Completed", "Cancelled"]) - if self.doc.production_item : - item_detail = webnotes.conn.sql("select name from `tabItem` where name = '%s' and docstatus != 2" - % self.doc.production_item, as_dict = 1) - if not item_detail: - msgprint("Item '%s' does not exist or cancelled in the system." - % cstr(self.doc.production_item), raise_exception=1) - + self.validate_bom_no() + self.validate_sales_order() + self.validate_warehouse() + + from utilities.transaction_base import validate_uom_is_integer + validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) + + def validate_bom_no(self): if self.doc.bom_no: bom = webnotes.conn.sql("""select name from `tabBOM` where name=%s and docstatus=1 and is_active=1 and item=%s""" @@ -37,16 +38,20 @@ class DocType: May be BOM not exists or inactive or not submitted or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1) + def validate_sales_order(self): if self.doc.sales_order: if not webnotes.conn.sql("""select name from `tabSales Order` where name=%s and docstatus = 1""", self.doc.sales_order): msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1) - + self.validate_production_order_against_so() - - from utilities.transaction_base import validate_uom_is_integer - validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"]) - + + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company + + for w in [self.doc.fg_warehouse, self.doc.wip_warehouse]: + validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_production_order_against_so(self): # already ordered qty diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py new file mode 100644 index 0000000000..0bfc400a8e --- /dev/null +++ b/patches/october_2013/p01_fix_serial_no_status.py @@ -0,0 +1,18 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import flt + +def execute(): + serial_nos = webnotes.conn.sql("""select name from `tabSerial No` where status!='Not in Use' + and docstatus=0""") + for sr in serial_nos: + sr_bean = webnotes.bean("Serial No", sr[0]) + sr_bean.make_controller().via_stock_ledger = True + sr_bean.run_method("validate") + sr_bean.save() + + webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in + ('Delivered', 'Purchase Returned')""") \ No newline at end of file diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py new file mode 100644 index 0000000000..d8cade78eb --- /dev/null +++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py @@ -0,0 +1,86 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import nowdate, nowtime, cstr +from accounts.utils import get_fiscal_year + +def execute(): + item_map = {} + for item in webnotes.conn.sql("""select * from tabItem""", as_dict=1): + item_map.setdefault(item.name, item) + + warehouse_map = get_warehosue_map() + naming_series = "STE/13/" + + for company in webnotes.conn.sql("select name from tabCompany"): + stock_entry = [{ + "doctype": "Stock Entry", + "naming_series": naming_series, + "posting_date": nowdate(), + "posting_time": nowtime(), + "purpose": "Material Transfer", + "company": company[0], + "remarks": "Material Transfer to activate perpetual inventory", + "fiscal_year": get_fiscal_year(nowdate())[0] + }] + expense_account = "Cost of Goods Sold - NISL" + cost_center = "Default CC Ledger - NISL" + + for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!='' + and ifnull(warehouse, '') in (%s) and ifnull(actual_qty, 0) != 0 + and (select company from tabWarehouse where name=bin.warehouse)=%s""" % + (', '.join(['%s']*len(warehouse_map)), '%s'), + (warehouse_map.keys() + [company[0]]), as_dict=1): + item_details = item_map[bin.item_code] + new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \ + if cstr(item_details.is_asset_item) == "Yes" \ + else warehouse_map[bin.warehouse].get("current_asset_warehouse") + + if item_details.has_serial_no == "Yes": + serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name + from `tabSerial No` where item_code = %s and warehouse = %s + and status in ('Available', 'Sales Returned')""", + (bin.item_code, bin.warehouse))]) + else: + serial_no = None + + stock_entry.append({ + "doctype": "Stock Entry Detail", + "parentfield": "mtn_details", + "s_warehouse": bin.warehouse, + "t_warehouse": new_warehouse, + "item_code": bin.item_code, + "description": item_details.description, + "qty": bin.actual_qty, + "transfer_qty": bin.actual_qty, + "uom": item_details.stock_uom, + "stock_uom": item_details.stock_uom, + "conversion_factor": 1, + "expense_account": expense_account, + "cost_center": cost_center, + "serial_no": serial_no + }) + + webnotes.bean(stock_entry).insert() + +def get_warehosue_map(): + return { + "MAHAPE": { + "current_asset_warehouse": "Mahape-New - NISL", + "fixed_asset_warehouse": "" + }, + "DROP SHIPMENT": { + "current_asset_warehouse": "Drop Shipment-New - NISL", + "fixed_asset_warehouse": "" + }, + "TRANSIT": { + "current_asset_warehouse": "Transit-New - NISL", + "fixed_asset_warehouse": "" + }, + "ASSET - MAHAPE": { + "current_asset_warehouse": "", + "fixed_asset_warehouse": "Assets-New - NISL" + } + } \ No newline at end of file diff --git a/patches/october_2013/set_stock_value_diff_in_sle.py b/patches/october_2013/set_stock_value_diff_in_sle.py new file mode 100644 index 0000000000..25f95e0e6d --- /dev/null +++ b/patches/october_2013/set_stock_value_diff_in_sle.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.utils import cint + +def execute(): + from patches.september_2012 import repost_stock + repost_stock.execute() \ No newline at end of file diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index b42a380758..3cc603fc34 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -121,4 +121,4 @@ def make_opportunity(source_name, target_doclist=None): } }}, target_doclist) - return [d.fields for d in doclist] \ No newline at end of file + return [d if isinstance(d, dict) else d.fields for d in doclist] diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt index 4f481b0a5e..b700a2e146 100644 --- a/selling/doctype/lead/lead.txt +++ b/selling/doctype/lead/lead.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-10 11:45:37", "docstatus": 0, - "modified": "2013-10-03 17:24:33", + "modified": "2013-10-09 15:27:54", "modified_by": "Administrator", "owner": "Administrator" }, @@ -159,8 +159,63 @@ "doctype": "DocField", "fieldname": "communication_history", "fieldtype": "Section Break", - "label": "Communication History", - "options": "icon-comments" + "label": "Communication", + "options": "icon-comments", + "print_hide": 1 + }, + { + "default": "__user", + "doctype": "DocField", + "fieldname": "lead_owner", + "fieldtype": "Link", + "in_filter": 1, + "label": "Lead Owner", + "oldfieldname": "lead_owner", + "oldfieldtype": "Link", + "options": "Profile", + "search_index": 1 + }, + { + "doctype": "DocField", + "fieldname": "col_break123", + "fieldtype": "Column Break", + "width": "50%" + }, + { + "allow_on_submit": 0, + "description": "Your sales person who will contact the lead in future", + "doctype": "DocField", + "fieldname": "contact_by", + "fieldtype": "Link", + "hidden": 0, + "in_filter": 1, + "label": "Next Contact By", + "oldfieldname": "contact_by", + "oldfieldtype": "Link", + "options": "Profile", + "print_hide": 0, + "reqd": 0, + "width": "100px" + }, + { + "allow_on_submit": 0, + "description": "Your sales person will get a reminder on this date to contact the lead", + "doctype": "DocField", + "fieldname": "contact_date", + "fieldtype": "Date", + "in_filter": 1, + "label": "Next Contact Date", + "no_copy": 1, + "oldfieldname": "contact_date", + "oldfieldtype": "Date", + "reqd": 0, + "width": "100px" + }, + { + "doctype": "DocField", + "fieldname": "sec_break123", + "fieldtype": "Section Break", + "options": "Simple" }, { "allow_on_submit": 0, @@ -273,18 +328,6 @@ "oldfieldtype": "Select", "options": "\nClient\nChannel Partner\nConsultant" }, - { - "default": "__user", - "doctype": "DocField", - "fieldname": "lead_owner", - "fieldtype": "Link", - "in_filter": 1, - "label": "Lead Owner", - "oldfieldname": "lead_owner", - "oldfieldtype": "Link", - "options": "Profile", - "search_index": 1 - }, { "doctype": "DocField", "fieldname": "market_segment", @@ -334,49 +377,6 @@ "oldfieldtype": "Column Break", "width": "50%" }, - { - "allow_on_submit": 0, - "description": "Your sales person who will contact the lead in future", - "doctype": "DocField", - "fieldname": "contact_by", - "fieldtype": "Link", - "hidden": 0, - "in_filter": 1, - "label": "Next Contact By", - "oldfieldname": "contact_by", - "oldfieldtype": "Link", - "options": "Profile", - "print_hide": 0, - "reqd": 0, - "width": "100px" - }, - { - "allow_on_submit": 0, - "description": "Your sales person will get a reminder on this date to contact the lead", - "doctype": "DocField", - "fieldname": "contact_date", - "fieldtype": "Date", - "in_filter": 1, - "label": "Next Contact Date", - "no_copy": 1, - "oldfieldname": "contact_date", - "oldfieldtype": "Date", - "reqd": 0, - "width": "100px" - }, - { - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "company", diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py index e63ce6b060..37672f2afb 100644 --- a/selling/doctype/opportunity/opportunity.py +++ b/selling/doctype/opportunity/opportunity.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate, cint +from webnotes.utils import cstr, cint from webnotes.model.bean import getlist from webnotes import msgprint, _ @@ -17,7 +17,7 @@ class DocType(TransactionBase): self.doclist = doclist self.fname = 'enq_details' self.tname = 'Opportunity Item' - + self._prev = webnotes._dict({ "contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \ (not cint(self.doc.fields.get("__islocal"))) else None, @@ -70,10 +70,6 @@ class DocType(TransactionBase): def on_update(self): - # Add to calendar - if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date: - webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date) - self.add_calendar_event() def add_calendar_event(self, opts=None, force=False): @@ -101,14 +97,6 @@ class DocType(TransactionBase): super(DocType, self).add_calendar_event(opts, force) - def set_last_contact_date(self): - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref - else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception - def validate_item_details(self): if not getlist(self.doclist, 'enquiry_details'): msgprint("Please select items for which enquiry needs to be made") @@ -122,7 +110,6 @@ class DocType(TransactionBase): def validate(self): self.set_status() - self.set_last_contact_date() self.validate_item_details() self.validate_uom_is_integer("uom", "qty") self.validate_lead_cust() diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt index 02caea0a6d..3c860ade84 100644 --- a/selling/doctype/opportunity/opportunity.txt +++ b/selling/doctype/opportunity/opportunity.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 18:50:30", "docstatus": 0, - "modified": "2013-10-03 16:30:58", + "modified": "2013-10-09 15:26:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -404,20 +404,6 @@ "oldfieldtype": "Date", "read_only": 0 }, - { - "allow_on_submit": 0, - "depends_on": "eval:!doc.__islocal", - "description": "Date on which the lead was last contacted", - "doctype": "DocField", - "fieldname": "last_contact_date", - "fieldtype": "Date", - "label": "Last Contact Date", - "no_copy": 1, - "oldfieldname": "last_contact_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "to_discuss", diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 697f805a2c..b6bc45d772 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, getdate +from webnotes.utils import cstr from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import _, msgprint @@ -97,24 +97,9 @@ class DocType(SellingController): msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation") raise Exception - #--------------Validation For Last Contact Date----------------- - # ==================================================================================================================== - def set_last_contact_date(self): - #if not self.doc.contact_date_ref: - #self.doc.contact_date_ref=self.doc.contact_date - #self.doc.last_contact_date=self.doc.contact_date_ref - if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date: - if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date): - self.doc.last_contact_date=self.doc.contact_date_ref - else: - msgprint("Contact Date Cannot be before Last Contact Date") - raise Exception - def validate(self): super(DocType, self).validate() - self.set_status() - self.set_last_contact_date() self.validate_order_type() self.validate_for_items() diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index af8ea1ad7a..0cdca58ce9 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -126,7 +126,7 @@ class DocType(SellingController): self.validate_po() self.validate_uom_is_integer("stock_uom", "qty") self.validate_for_items() - self.validate_warehouse_user() + self.validate_warehouse() sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_active_sales_items(self) sales_com_obj.check_conversion_rate(self) @@ -147,14 +147,15 @@ class DocType(SellingController): if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered' - def validate_warehouse_user(self): - from stock.utils import validate_warehouse_user + def validate_warehouse(self): + from stock.utils import validate_warehouse_user, validate_warehouse_company warehouses = list(set([d.reserved_warehouse for d in self.doclist.get({"doctype": self.tname}) if d.reserved_warehouse])) for w in warehouses: validate_warehouse_user(w) + validate_warehouse_company(w, self.doc.company) def validate_with_previous_doc(self): super(DocType, self).validate_with_previous_doc(self.tname, { diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py index 801d82bf40..6e74ac4869 100644 --- a/selling/utils/__init__.py +++ b/selling/utils/__init__.py @@ -74,7 +74,7 @@ def get_item_details(args): out.update(apply_pos_settings(pos_settings, out)) if args.doctype in ("Sales Invoice", "Delivery Note"): - if item_bean.doc.has_serial_no and not args.serial_no: + if item_bean.doc.has_serial_no == "Yes" and not args.serial_no: out.serial_no = _get_serial_nos_by_fifo(args, item_bean) return out diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index b27d0345ea..b20e790af7 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -186,7 +186,6 @@ class DocType(SellingController): # create stock ledger entry self.update_stock_ledger() - self.update_serial_nos() self.credit_limit() @@ -204,42 +203,12 @@ class DocType(SellingController): self.update_prevdoc_status() self.update_stock_ledger() - self.update_serial_nos(cancel=True) webnotes.conn.set(self.doc, 'status', 'Cancelled') self.cancel_packing_slips() self.make_cancel_gl_entries() - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Delivery Note", "delivery_note_details") - update_serial_nos_after_submit(self, "Delivery Note", "packing_details") - - for table_fieldname in ("delivery_note_details", "packing_details"): - for d in self.doclist.get({"parentfield": table_fieldname}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.status = "Available" - for fieldname in ("warranty_expiry_date", "delivery_document_type", - "delivery_document_no", "delivery_date", "delivery_time", "customer", - "customer_name"): - sr.doc.fields[fieldname] = None - else: - sr.doc.delivery_document_type = "Delivery Note" - sr.doc.delivery_document_no = self.doc.name - sr.doc.delivery_date = self.doc.posting_date - sr.doc.delivery_time = self.doc.posting_time - sr.doc.customer = self.doc.customer - sr.doc.customer_name = self.doc.customer_name - if sr.doc.warranty_period: - sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date), - cint(sr.doc.warranty_period)) - sr.doc.status = 'Delivered' - - sr.save() - def validate_packed_qty(self): """ Validate that if packed qty exists, it should be equal to qty diff --git a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py index f431537c6c..89a3b81d57 100644 --- a/stock/doctype/landed_cost_wizard/landed_cost_wizard.py +++ b/stock/doctype/landed_cost_wizard/landed_cost_wizard.py @@ -85,7 +85,6 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty", is_cancelled="Yes") - pr_bean.run_method("update_serial_nos", cancel=True) webnotes.conn.sql("""delete from `tabStock Ledger Entry` where voucher_type='Purchase Receipt' and voucher_no=%s""", pr) @@ -97,5 +96,4 @@ class DocType: pr_bean = webnotes.bean("Purchase Receipt", pr) pr_bean.run_method("update_ordered_qty") pr_bean.run_method("update_stock") - pr_bean.run_method("update_serial_nos") - pr_bean.run_method("make_gl_entries") + pr_bean.run_method("make_gl_entries") \ No newline at end of file diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index 249062f29d..d1672ba12c 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -68,22 +68,14 @@ class DocType(BuyingController): self.doc.status = "Draft" import utilities - utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", - "Cancelled"]) + utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "Cancelled"]) - # restrict material request type self.validate_value("material_request_type", "in", ["Purchase", "Transfer"]) - # Get Purchase Common Obj pc_obj = get_obj(dt='Purchase Common') - - - # Validate for items pc_obj.validate_for_items(self) - - # Validate qty against SO - self.validate_qty_against_so() + self.validate_qty_against_so() def update_bin(self, is_submit, is_stopped): """ Update Quantity Requested for Purchase in Bin for Material Request of type 'Purchase'""" diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 7d663b8778..6169b1d916 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -246,26 +246,12 @@ class DocType(BuyingController): self.update_stock() - self.update_serial_nos() + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") purchase_controller.update_last_purchase_rate(self, 1) self.make_gl_entries() - - def update_serial_nos(self, cancel=False): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") - - for d in self.doclist.get({"parentfield": "purchase_receipt_details"}): - for serial_no in get_serial_nos(d.serial_no): - sr = webnotes.bean("Serial No", serial_no) - if cancel: - sr.doc.supplier = None - sr.doc.supplier_name = None - else: - sr.doc.supplier = self.doc.supplier - sr.doc.supplier_name = self.doc.supplier_name - sr.save() def check_next_docstatus(self): submit_rv = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_receipt = '%s' and t1.docstatus = 1" % (self.doc.name)) @@ -292,7 +278,6 @@ class DocType(BuyingController): self.update_ordered_qty() self.update_stock() - self.update_serial_nos(cancel=True) self.update_prevdoc_status() pc_obj.update_last_purchase_rate(self, 0) @@ -308,7 +293,7 @@ class DocType(BuyingController): def get_rate(self,arg): return get_obj('Purchase Common').get_rate(arg,self) - + def get_gl_entries_for_stock(self, warehouse_account=None): against_stock_account = self.get_company_default("stock_received_but_not_billed") diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 3b9704fcd5..93836d64e4 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -4,14 +4,22 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, getdate, nowdate +from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days import datetime -from webnotes import msgprint, _ +from webnotes import msgprint, _, ValidationError from controllers.stock_controller import StockController -class SerialNoCannotCreateDirectError(webnotes.ValidationError): pass -class SerialNoCannotCannotChangeError(webnotes.ValidationError): pass +class SerialNoCannotCreateDirectError(ValidationError): pass +class SerialNoCannotCannotChangeError(ValidationError): pass +class SerialNoNotRequiredError(ValidationError): pass +class SerialNoRequiredError(ValidationError): pass +class SerialNoQtyError(ValidationError): pass +class SerialNoItemError(ValidationError): pass +class SerialNoWarehouseError(ValidationError): pass +class SerialNoStatusError(ValidationError): pass +class SerialNoNotExistsError(ValidationError): pass +class SerialNoDuplicateError(ValidationError): pass class DocType(StockController): def __init__(self, doc, doclist=None): @@ -21,13 +29,18 @@ class DocType(StockController): def validate(self): if self.doc.fields.get("__islocal") and self.doc.warehouse: - webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be set by Stock Entry or Purchase Receipt"), - SerialNoCannotCreateDirectError) + webnotes.throw(_("New Serial No cannot have Warehouse. Warehouse must be \ + set by Stock Entry or Purchase Receipt"), SerialNoCannotCreateDirectError) self.validate_warranty_status() self.validate_amc_status() self.validate_warehouse() self.validate_item() + + if self.via_stock_ledger: + self.set_status() + self.set_purchase_details() + self.set_sales_details() def validate_amc_status(self): """ @@ -41,7 +54,8 @@ class DocType(StockController): validate warranty status """ if (self.doc.maintenance_status == 'Out of Warranty' and self.doc.warranty_expiry_date and getdate(self.doc.warranty_expiry_date) >= datetime.date.today()) or (self.doc.maintenance_status == 'Under Warranty' and (not self.doc.warranty_expiry_date or getdate(self.doc.warranty_expiry_date) < datetime.date.today())): - msgprint("Warranty expiry date and maintenance status mismatch. Please verify", raise_exception=1) + msgprint("Warranty expiry date and maintenance status mismatch. Please verify", + raise_exception=1) def validate_warehouse(self): @@ -49,10 +63,11 @@ class DocType(StockController): item_code, warehouse = webnotes.conn.get_value("Serial No", self.doc.name, ["item_code", "warehouse"]) if item_code != self.doc.item_code: - webnotes.throw(_("Item Code cannot be changed for Serial No."), SerialNoCannotCannotChangeError) + webnotes.throw(_("Item Code cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) if not self.via_stock_ledger and warehouse != self.doc.warehouse: - webnotes.throw(_("Warehouse cannot be changed for Serial No."), SerialNoCannotCannotChangeError) - + webnotes.throw(_("Warehouse cannot be changed for Serial No."), + SerialNoCannotCannotChangeError) def validate_item(self): """ @@ -67,16 +82,89 @@ class DocType(StockController): self.doc.item_name = item.item_name self.doc.brand = item.brand self.doc.warranty_period = item.warranty_period - + + def set_status(self): + last_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and ifnull(is_cancelled, 'No')='No' + order by name desc limit 1""", + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, + self.doc.item_code), as_dict=1) + + if last_sle: + if last_sle[0].voucher_type == "Stock Entry": + document_type = webnotes.conn.get_value("Stock Entry", last_sle[0].voucher_no, + "purpose") + else: + document_type = last_sle[0].voucher_type + + if last_sle[0].actual_qty > 0: + if document_type == "Sales Return": + self.doc.status = "Sales Returned" + else: + self.doc.status = "Available" + else: + if document_type == "Purchase Return": + self.doc.status = "Purchase Returned" + elif last_sle[0].voucher_type in ("Delivery Note", "Sales Invoice"): + self.doc.status = "Delivered" + else: + self.doc.status = "Not Available" + + def set_purchase_details(self): + purchase_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty > 0 + and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, + self.doc.item_code), as_dict=1) + + if purchase_sle: + self.doc.purchase_document_type = purchase_sle[0].voucher_type + self.doc.purchase_document_no = purchase_sle[0].voucher_no + self.doc.purchase_date = purchase_sle[0].posting_date + self.doc.purchase_time = purchase_sle[0].posting_time + self.doc.purchase_rate = purchase_sle[0].incoming_rate + if purchase_sle[0].voucher_type == "Purchase Receipt": + self.doc.supplier, self.doc.supplier_name = \ + webnotes.conn.get_value("Purchase Receipt", purchase_sle[0].voucher_no, + ["supplier", "supplier_name"]) + else: + for fieldname in ("purchase_document_type", "purchase_document_no", + "purchase_date", "purchase_time", "purchase_rate", "supplier", "supplier_name"): + self.doc.fields[fieldname] = None + + def set_sales_details(self): + delivery_sle = webnotes.conn.sql("""select * from `tabStock Ledger Entry` + where (serial_no like %s or serial_no like %s or serial_no=%s) + and item_code=%s and actual_qty<0 + and voucher_type in ('Delivery Note', 'Sales Invoice') + and ifnull(is_cancelled, 'No')='No' order by name desc limit 1""", + ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, + self.doc.item_code), as_dict=1) + if delivery_sle: + self.doc.delivery_document_type = delivery_sle[0].voucher_type + self.doc.delivery_document_no = delivery_sle[0].voucher_no + self.doc.delivery_date = delivery_sle[0].posting_date + self.doc.delivery_time = delivery_sle[0].posting_time + self.doc.customer, self.doc.customer_name = \ + webnotes.conn.get_value(delivery_sle[0].voucher_type, delivery_sle[0].voucher_no, + ["customer", "customer_name"]) + if self.doc.warranty_period: + self.doc.warranty_expiry_date = add_days(cstr(delivery_sle[0].posting_date), + cint(self.doc.warranty_period)) + else: + for fieldname in ("delivery_document_type", "delivery_document_no", + "delivery_date", "delivery_time", "customer", "customer_name", + "warranty_expiry_date"): + self.doc.fields[fieldname] = None + def on_trash(self): if self.doc.status == 'Delivered': - msgprint("Cannot trash Serial No : %s as it is already Delivered" % (self.doc.name), raise_exception = 1) + webnotes.throw(_("Delivered Serial No ") + self.doc.name + _(" can not be deleted")) if self.doc.warehouse: - webnotes.throw(_("Cannot delete Serial No in warehouse. First remove from warehouse, then delete.") + \ - ": " + self.doc.name) - - def on_cancel(self): - self.on_trash() + webnotes.throw(_("Cannot delete Serial No in warehouse. \ + First remove from warehouse, then delete.") + ": " + self.doc.name) def on_rename(self, new, old, merge=False): """rename serial_no text fields""" @@ -93,3 +181,106 @@ class DocType(StockController): webnotes.conn.sql("""update `tab%s` set serial_no = %s where name=%s""" % (dt[0], '%s', '%s'), ('\n'.join(serial_nos), item[0])) + +def process_serial_no(sle): + item_det = get_item_details(sle.item_code) + validate_serial_no(sle, item_det) + update_serial_nos(sle, item_det) + +def validate_serial_no(sle, item_det): + if item_det.has_serial_no=="No": + if sle.serial_no: + webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + + sle.item_code), SerialNoNotRequiredError) + else: + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + if cint(sle.actual_qty) != flt(sle.actual_qty): + webnotes.throw(_("Serial No qty cannot be a fraction") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty))) + if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)): + webnotes.throw(_("Serial Nos do not match with qty") + \ + (": %s (%s)" % (sle.item_code, sle.actual_qty)), SerialNoQtyError) + + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + + if sr.doc.item_code!=sle.item_code: + webnotes.throw(_("Serial No does not belong to Item") + + (": %s (%s)" % (sle.item_code, serial_no)), SerialNoItemError) + + if sr.doc.warehouse and sle.actual_qty > 0: + webnotes.throw(_("Same Serial No") + ": " + sr.doc.name + + _(" can not be received twice"), SerialNoDuplicateError) + + if sle.actual_qty < 0: + if sr.doc.warehouse!=sle.warehouse: + webnotes.throw(_("Serial No") + ": " + serial_no + + _(" does not belong to Warehouse") + ": " + sle.warehouse, + SerialNoWarehouseError) + + if sle.voucher_type in ("Delivery Note", "Sales Invoice") \ + and sr.doc.status != "Available": + webnotes.throw(_("Serial No status must be 'Available' to Deliver") + + ": " + serial_no, SerialNoStatusError) + elif sle.actual_qty < 0: + # transfer out + webnotes.throw(_("Serial No must exist to transfer out.") + \ + ": " + serial_no, SerialNoNotExistsError) + elif not item_det.serial_no_series: + webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + + sle.item_code), SerialNoRequiredError) + +def update_serial_nos(sle, item_det): + if sle.serial_no: + serial_nos = get_serial_nos(sle.serial_no) + for serial_no in serial_nos: + if webnotes.conn.exists("Serial No", serial_no): + sr = webnotes.bean("Serial No", serial_no) + sr.make_controller().via_stock_ledger = True + sr.doc.warehouse = sle.warehouse if sle.actual_qty > 0 else None + sr.save() + elif sle.actual_qty > 0: + make_serial_no(serial_no, sle) + elif sle.actual_qty > 0 and item_det.serial_no_series: + from webnotes.model.doc import make_autoname + serial_nos = [] + for i in xrange(cint(sle.actual_qty)): + serial_nos.append(make_serial_no(make_autoname(item_det.serial_no_series), sle)) + sle.serial_no = "\n".join(serial_nos) + +def get_item_details(item_code): + return webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", item_code, as_dict=True)[0] + +def get_serial_nos(serial_no): + return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] + +def make_serial_no(serial_no, sle): + sr = webnotes.new_bean("Serial No") + sr.doc.serial_no = serial_no + sr.doc.item_code = sle.item_code + sr.make_controller().via_stock_ledger = True + sr.insert() + sr.doc.warehouse = sle.warehouse + sr.doc.status = "Available" + sr.save() + webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) + return sr.doc.name + +def update_serial_nos_after_submit(controller, parenttype, parentfield): + if not hasattr(webnotes, "new_stock_ledger_entries"): + return + + for d in controller.doclist.get({"parentfield": parentfield}): + serial_no = None + for sle in webnotes.new_stock_ledger_entries: + if sle.voucher_detail_no==d.name: + serial_no = sle.serial_no + break + + if d.serial_no != serial_no: + d.serial_no = serial_no + webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 535d4c8233..0117864a1b 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -51,13 +51,15 @@ class DocType(StockController): def on_submit(self): self.update_stock_ledger() - self.update_serial_no(1) + + from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit + update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") + self.update_production_order(1) self.make_gl_entries() def on_cancel(self): self.update_stock_ledger() - self.update_serial_no(0) self.update_production_order(0) self.make_cancel_gl_entries() @@ -293,24 +295,6 @@ class DocType(StockController): from `tabStock Entry Detail` where parent in ( select name from `tabStock Entry` where `%s`=%s and docstatus=1) group by item_code""" % (ref_fieldname, "%s"), (self.doc.fields.get(ref_fieldname),))) - - def update_serial_no(self, is_submit): - """Create / Update Serial No""" - - from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos - update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") - - for d in getlist(self.doclist, 'mtn_details'): - for serial_no in get_serial_nos(d.serial_no): - if self.doc.purpose == 'Purchase Return': - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Purchase Returned" if is_submit else "Available" - sr.save() - - if self.doc.purpose == "Sales Return": - sr = webnotes.bean("Serial No", serial_no) - sr.doc.status = "Sales Returned" if is_submit else "Delivered" - sr.save() def update_stock_ledger(self): sl_entries = [] diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index e2358eba4f..b41a6269ad 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import webnotes, unittest from webnotes.utils import flt -from stock.doctype.stock_ledger_entry.stock_ledger_entry import * +from stock.doctype.serial_no.serial_no import * from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory @@ -48,7 +48,7 @@ class TestStockEntry(unittest.TestCase): webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - from stock.doctype.stock_ledger_entry.stock_ledger_entry import InvalidWarehouseCompany + from stock.utils import InvalidWarehouseCompany st1 = webnotes.bean(copy=test_records[0]) st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() @@ -721,6 +721,18 @@ class TestStockEntry(unittest.TestCase): se.insert() self.assertRaises(SerialNoNotExistsError, se.submit) + def test_serial_duplicate(self): + self._clear_stock_account_balance() + self.test_serial_by_series() + + se = webnotes.bean(copy=test_records[0]) + se.doclist[1].item_code = "_Test Serialized Item With Series" + se.doclist[1].qty = 1 + se.doclist[1].serial_no = "ABCD00001" + se.doclist[1].transfer_qty = 1 + se.insert() + self.assertRaises(SerialNoDuplicateError, se.submit) + def test_serial_by_series(self): self._clear_stock_account_balance() se = make_serialized_item() diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 1c3d3e132d..8fef889f72 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -3,29 +3,17 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint, ValidationError +from webnotes import _, msgprint from webnotes.utils import cint, flt, getdate, cstr from webnotes.model.controller import DocListController -class InvalidWarehouseCompany(ValidationError): pass -class SerialNoNotRequiredError(ValidationError): pass -class SerialNoRequiredError(ValidationError): pass -class SerialNoQtyError(ValidationError): pass -class SerialNoItemError(ValidationError): pass -class SerialNoWarehouseError(ValidationError): pass -class SerialNoStatusError(ValidationError): pass -class SerialNoNotExistsError(ValidationError): pass - -def get_serial_nos(serial_no): - return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()] - class DocType(DocListController): def __init__(self, doc, doclist=[]): self.doc = doc self.doclist = doclist def validate(self): - from stock.utils import validate_warehouse_user + from stock.utils import validate_warehouse_user, validate_warehouse_company if not hasattr(webnotes, "new_stock_ledger_entries"): webnotes.new_stock_ledger_entries = [] @@ -33,7 +21,7 @@ class DocType(DocListController): self.validate_mandatory() self.validate_item() validate_warehouse_user(self.doc.warehouse) - self.validate_warehouse_company() + validate_warehouse_company(self.doc.warehouse, self.doc.company) self.scrub_posting_time() from accounts.utils import validate_fiscal_year @@ -42,7 +30,9 @@ class DocType(DocListController): def on_submit(self): self.check_stock_frozen_date() self.actual_amt_check() - self.validate_serial_no() + + from stock.doctype.serial_no.serial_no import process_serial_no + process_serial_no(self.doc) #check for item quantity available in stock def actual_amt_check(self): @@ -63,13 +53,6 @@ class DocType(DocListController): as on %(posting_date)s %(posting_time)s""" % self.doc.fields) sself.doc.fields.pop('batch_bal') - - def validate_warehouse_company(self): - warehouse_company = webnotes.conn.get_value("Warehouse", self.doc.warehouse, "company") - if warehouse_company and warehouse_company != self.doc.company: - webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ - self.doc.warehouse + ", " + self.doc.company +")", - raise_exception=InvalidWarehouseCompany) def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] @@ -81,7 +64,10 @@ class DocType(DocListController): msgprint("Warehouse: '%s' does not exist in the system. Please check." % self.doc.fields.get(k), raise_exception = 1) def validate_item(self): - item_det = self.get_item_details() + item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus, + is_stock_item, has_serial_no, serial_no_series + from tabItem where name=%s""", + self.doc.item_code, as_dict=True)[0] if item_det.is_stock_item != 'Yes': webnotes.throw("""Item: "%s" is not a Stock Item.""" % self.doc.item_code) @@ -99,95 +85,6 @@ class DocType(DocListController): if not self.doc.stock_uom: self.doc.stock_uom = item_det.stock_uom - def get_item_details(self): - return webnotes.conn.sql("""select name, has_batch_no, docstatus, - is_stock_item, has_serial_no, serial_no_series - from tabItem where name=%s""", - self.doc.item_code, as_dict=True)[0] - - def validate_serial_no(self): - item_det = self.get_item_details() - - if item_det.has_serial_no=="No": - if self.doc.serial_no: - webnotes.throw(_("Serial Number should be blank for Non Serialized Item" + ": " + self.doc.item), - SerialNoNotRequiredError) - else: - if self.doc.serial_no: - serial_nos = get_serial_nos(self.doc.serial_no) - if cint(self.doc.actual_qty) != flt(self.doc.actual_qty): - webnotes.throw(_("Serial No qty cannot be a fraction") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty))) - if len(serial_nos) and len(serial_nos) != abs(cint(self.doc.actual_qty)): - webnotes.throw(_("Serial Nos do not match with qty") + \ - (": %s (%s)" % (self.doc.item_code, self.doc.actual_qty)), SerialNoQtyError) - - # check serial no exists, if yes then source - for serial_no in serial_nos: - if webnotes.conn.exists("Serial No", serial_no): - sr = webnotes.bean("Serial No", serial_no) - - if sr.doc.item_code!=self.doc.item_code: - webnotes.throw(_("Serial No does not belong to Item") + \ - (": %s (%s)" % (self.doc.item_code, serial_no)), SerialNoItemError) - - sr.make_controller().via_stock_ledger = True - - if self.doc.actual_qty < 0: - if sr.doc.warehouse!=self.doc.warehouse: - webnotes.throw(_("Serial No") + ": " + serial_no + - _(" does not belong to Warehouse") + ": " + self.doc.warehouse, - SerialNoWarehouseError) - - if self.doc.voucher_type in ("Delivery Note", "Sales Invoice") \ - and sr.doc.status != "Available": - webnotes.throw(_("Serial No status must be 'Available' to Deliver") - + ": " + serial_no, SerialNoStatusError) - - - sr.doc.warehouse = None - sr.save() - else: - sr.doc.warehouse = self.doc.warehouse - sr.save() - else: - if self.doc.actual_qty < 0: - # transfer out - webnotes.throw(_("Serial No must exist to transfer out.") + \ - ": " + serial_no, SerialNoNotExistsError) - else: - # transfer in - self.make_serial_no(serial_no) - else: - if item_det.serial_no_series: - from webnotes.model.doc import make_autoname - serial_nos = [] - for i in xrange(cint(self.doc.actual_qty)): - serial_nos.append(self.make_serial_no(make_autoname(item_det.serial_no_series))) - self.doc.serial_no = "\n".join(serial_nos) - else: - webnotes.throw(_("Serial Number Required for Serialized Item" + ": " + self.doc.item), - SerialNoRequiredError) - - def make_serial_no(self, serial_no): - sr = webnotes.new_bean("Serial No") - sr.doc.serial_no = serial_no - sr.doc.item_code = self.doc.item_code - sr.doc.purchase_rate = self.doc.incoming_rate - sr.doc.purchase_document_type = self.doc.voucher_type - sr.doc.purchase_document_no = self.doc.voucher_no - sr.doc.purchase_date = self.doc.posting_date - sr.doc.purchase_time = self.doc.posting_time - sr.make_controller().via_stock_ledger = True - sr.insert() - - # set warehouse - sr.doc.warehouse = self.doc.warehouse - sr.doc.status = "Available" - sr.save() - webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) - return sr.doc.name - def check_stock_frozen_date(self): stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or '' if stock_frozen_upto: @@ -199,21 +96,6 @@ class DocType(DocListController): if not self.doc.posting_time or self.doc.posting_time == '00:0': self.doc.posting_time = '00:00' -def update_serial_nos_after_submit(controller, parenttype, parentfield): - if not hasattr(webnotes, "new_stock_ledger_entries"): - return - - for d in controller.doclist.get({"parentfield": parentfield}): - serial_no = None - for sle in webnotes.new_stock_ledger_entries: - if sle.voucher_detail_no==d.name: - serial_no = sle.serial_no - break - - if d.serial_no != serial_no: - d.serial_no = serial_no - webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no) - def on_doctype_update(): if not webnotes.conn.sql("""show index from `tabStock Ledger Entry` where Key_name="posting_sort_index" """): diff --git a/stock/utils.py b/stock/utils.py index 8836c6c991..1f501644ff 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -9,6 +9,7 @@ from webnotes.defaults import get_global_default from webnotes.utils.email_lib import sendmail class UserNotAllowedForWarehouse(webnotes.ValidationError): pass +class InvalidWarehouseCompany(webnotes.ValidationError): pass def get_stock_balance_on(warehouse, posting_date=None): if not posting_date: posting_date = nowdate() @@ -216,6 +217,12 @@ def validate_warehouse_user(warehouse): if warehouse_users and not (webnotes.session.user in warehouse_users): webnotes.throw(_("Not allowed entry in Warehouse") \ + ": " + warehouse, UserNotAllowedForWarehouse) + +def validate_warehouse_company(warehouse, company): + warehouse_company = webnotes.conn.get_value("Warehouse", warehouse, "company") + if warehouse_company and warehouse_company != company: + webnotes.msgprint(_("Warehouse does not belong to company.") + " (" + \ + warehouse + ", " + company +")", raise_exception=InvalidWarehouseCompany) def get_sales_bom_buying_amount(item_code, warehouse, voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries, item_sales_bom): diff --git a/support/report/maintenance_schedules/maintenance_schedules.txt b/support/report/maintenance_schedules/maintenance_schedules.txt index 525f4834ba..766eb20151 100644 --- a/support/report/maintenance_schedules/maintenance_schedules.txt +++ b/support/report/maintenance_schedules/maintenance_schedules.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-06 14:25:21", "docstatus": 0, - "modified": "2013-05-06 14:32:47", + "modified": "2013-10-09 12:23:27", "modified_by": "Administrator", "owner": "Administrator" }, @@ -10,7 +10,7 @@ "doctype": "Report", "is_standard": "Yes", "name": "__common__", - "query": "SELECT\n ms_item.scheduled_date as \"Schedule Date:Date:120\",\n\tms_item.item_code as \"Item Code:Link/Item:120\",\n\tms_item.item_name as \"Item Name::120\",\n\tms_item.serial_no as \"Serial No::120\",\n\tms_item.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms.sales_order_no as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, `tabMaintenance Schedule Detail` ms_item\nWHERE\n\tms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_item.scheduled_date asc, ms_item.item_code asc", + "query": "SELECT\n ms_sch.scheduled_date as \"Schedule Date:Date:120\",\n\tms_sch.item_code as \"Item Code:Link/Item:120\",\n\tms_sch.item_name as \"Item Name::120\",\n\tms_sch.serial_no as \"Serial No::120\",\n\tms_sch.incharge_name as \"Incharge::120\",\n\tms.customer_name as \"Customer:Link/Customer:120\",\n\tms.address_display as \"Customer Address::120\",\n\tms_item.prevdoc_docname as \"Sales Order:Link/Sales Order:120\",\n\tms.company as \"Company:Link/Company:120\"\n\t\nFROM\n\t`tabMaintenance Schedule` ms, \n `tabMaintenance Schedule Detail` ms_sch, \n `tabMaintenance Schedule Item` ms_item\nWHERE\n\tms.name = ms_sch.parent and ms.name = ms_item.parent and ms.docstatus = 1\nORDER BY\n\tms_sch.scheduled_date asc, ms_sch.item_code asc", "ref_doctype": "Maintenance Schedule", "report_name": "Maintenance Schedules", "report_type": "Query Report" From f56d73c9bc17663b1ab0918a4164d663af70e0fc Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Oct 2013 16:35:09 +0530 Subject: [PATCH 099/123] [minor] removed get_rate --- .../purchase_invoice/purchase_invoice.py | 8 -------- .../purchase_taxes_and_charges_master.js | 16 ++------------- .../purchase_taxes_and_charges_master.py | 7 +------ .../doctype/sales_invoice/sales_invoice.py | 8 +------- .../sales_taxes_and_charges_master.js | 18 +++-------------- .../sales_taxes_and_charges_master.py | 6 +----- .../purchase_common/purchase_common.js | 1 + .../purchase_common/purchase_common.py | 15 -------------- .../doctype/purchase_order/purchase_order.py | 7 ------- controllers/accounts_controller.py | 4 ++++ controllers/buying_controller.py | 5 ++++- public/js/controllers/accounts.js | 18 +++++++++++++++++ selling/doctype/quotation/quotation.py | 6 ------ selling/doctype/sales_common/sales_common.js | 1 + selling/doctype/sales_common/sales_common.py | 20 ------------------- selling/doctype/sales_order/sales_order.py | 3 --- stock/doctype/delivery_note/delivery_note.py | 3 --- .../material_request/material_request.py | 4 ---- .../purchase_receipt/purchase_receipt.py | 8 -------- 19 files changed, 36 insertions(+), 122 deletions(-) create mode 100644 public/js/controllers/accounts.js diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index c79bfd6648..a562c67a38 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -88,14 +88,6 @@ class DocType(BuyingController): super(DocType, self).get_advances(self.doc.credit_to, "Purchase Invoice Advance", "advance_allocation_details", "debit") - def get_rate(self,arg): - return get_obj('Purchase Common').get_rate(arg,self) - - def get_rate1(self,acc): - rate = webnotes.conn.sql("select tax_rate from `tabAccount` where name='%s'"%(acc)) - ret={'add_tax_rate' :rate and flt(rate[0][0]) or 0 } - return ret - def check_active_purchase_items(self): for d in getlist(self.doclist, 'entries'): if d.item_code: # extra condn coz item_code is not mandatory in PV diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js index 423c4e49b9..3368773601 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js @@ -4,6 +4,8 @@ // //--------- ONLOAD ------------- +wn.require("app/js/controllers/accounts.js"); + cur_frm.cscript.onload = function(doc, cdt, cdn) { } @@ -134,20 +136,6 @@ cur_frm.fields_dict['purchase_tax_details'].grid.get_field("cost_center").get_qu } } -cur_frm.cscript.account_head = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - if(!d.charge_type && d.account_head){ - alert("Please select Charge Type first"); - validated = false; - d.account_head = ''; - } - else if(d.account_head && d.charge_type) { - arg = "{'charge_type' : '" + d.charge_type + "', 'account_head' : '" + d.account_head + "'}"; - return get_server_fields('get_rate', arg, 'purchase_tax_details', doc, cdt, cdn, 1); - } - refresh_field('account_head',d.name,'purchase_tax_details'); -} - cur_frm.cscript.rate = function(doc, cdt, cdn) { var d = locals[cdt][cdn]; if(!d.charge_type && d.rate) { diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py index 0a32fb972d..3d003f6e93 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py @@ -14,9 +14,4 @@ from webnotes.model.code import get_obj class DocType: def __init__(self, doc, doclist=[]): self.doc = doc - self.doclist = doclist - - # Get Tax Rate if account type is Tax - # =================================================================== - def get_rate(self, arg): - return get_obj('Purchase Common').get_rate(arg, self) \ No newline at end of file + self.doclist = doclist \ No newline at end of file diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 5c7597c403..92c168008a 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -264,13 +264,7 @@ class DocType(SellingController): def get_adj_percent(self, arg=''): """Fetch ref rate from item master as per selected price list""" - get_obj('Sales Common').get_adj_percent(self) - - - def get_rate(self,arg): - """Get tax rate if account type is tax""" - get_obj('Sales Common').get_rate(arg) - + get_obj('Sales Common').get_adj_percent(self) def get_comm_rate(self, sales_partner): """Get Commission rate of Sales Partner""" diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js index f1a602738b..d8f55fdd50 100644 --- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js +++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js @@ -2,6 +2,9 @@ // License: GNU General Public License v3. See license.txt //--------- ONLOAD ------------- + +wn.require("app/js/controllers/accounts.js"); + cur_frm.cscript.onload = function(doc, cdt, cdn) { if(doc.doctype === "Sales Taxes and Charges Master") erpnext.add_for_territory(); @@ -142,21 +145,6 @@ cur_frm.fields_dict['other_charges'].grid.get_field("cost_center").get_query = f } } - -cur_frm.cscript.account_head = function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - if(!d.charge_type && d.account_head){ - alert("Please select Charge Type first"); - validated = false; - d.account_head = ''; - } - else if(d.account_head && d.charge_type) { - arg = "{'charge_type' : '" + d.charge_type +"', 'account_head' : '" + d.account_head + "'}"; - return get_server_fields('get_rate', arg, 'other_charges', doc, cdt, cdn, 1); - } - refresh_field('account_head',d.name,'other_charges'); -} - cur_frm.cscript.rate = function(doc, cdt, cdn) { var d = locals[cdt][cdn]; if(!d.charge_type && d.rate) { diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py index 019edcb31b..67ba9cb8ad 100644 --- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py +++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py @@ -6,11 +6,7 @@ import webnotes from webnotes.utils import cint from webnotes.model.controller import DocListController -class DocType(DocListController): - def get_rate(self, arg): - from webnotes.model.code import get_obj - return get_obj('Sales Common').get_rate(arg) - +class DocType(DocListController): def validate(self): if self.doc.is_default == 1: webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0 diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 433a76fba7..023c7f3a63 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -8,6 +8,7 @@ wn.provide("erpnext.buying"); wn.require("app/js/transaction.js"); +wn.require("app/js/controllers/accounts.js"); erpnext.buying.BuyingController = erpnext.TransactionController.extend({ onload: function() { diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py index c05aba4883..1d57f88910 100644 --- a/buying/doctype/purchase_common/purchase_common.py +++ b/buying/doctype/purchase_common/purchase_common.py @@ -36,13 +36,6 @@ class DocType(BuyingController): msgprint("Supplier : %s does not exists" % (name)) raise Exception - # Get Available Qty at Warehouse - def get_bin_details( self, arg = ''): - arg = eval(arg) - bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (arg['item_code'], arg['warehouse']), as_dict=1) - ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 } - return ret - def update_last_purchase_rate(self, obj, is_submit): """updates last_purchase_rate in item table for each item""" @@ -197,14 +190,6 @@ class DocType(BuyingController): msgprint(cstr(doctype) + ": " + cstr(submitted[0][0]) + _(" not submitted"), raise_exception=1) - def get_rate(self, arg, obj): - arg = eval(arg) - rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = %s" - , (arg['account_head']), as_dict=1) - - return {'rate': rate and (rate[0]['account_type'] == 'Tax' \ - and not arg['charge_type'] == 'Actual') and flt(rate[0]['tax_rate']) or 0 } - def get_prevdoc_date(self, obj): for d in getlist(obj.doclist, obj.fname): if d.prevdoc_doctype and d.prevdoc_docname: diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py index 3389f7419a..dc75466a4b 100644 --- a/buying/doctype/purchase_order/purchase_order.py +++ b/buying/doctype/purchase_order/purchase_order.py @@ -65,10 +65,6 @@ class DocType(BuyingController): } }) - # get available qty at warehouse - def get_bin_details(self, arg = ''): - return get_obj(dt='Purchase Common').get_bin_details(arg) - def get_schedule_dates(self): for d in getlist(self.doclist, 'po_details'): if d.prevdoc_detail_docname and not d.schedule_date: @@ -185,9 +181,6 @@ class DocType(BuyingController): def on_update(self): pass - def get_rate(self,arg): - return get_obj('Purchase Common').get_rate(arg,self) - @webnotes.whitelist() def make_purchase_receipt(source_name, target_doclist=None): from webnotes.model.mapper import get_mapped_doclist diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 927b24980f..f290d4d747 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -423,3 +423,7 @@ class AccountsController(TransactionBase): self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") return self._abbr + +@webnotes.whitelist() +def get_tax_rate(account_head): + return webnotes.conn.get_value("Account", account_head, "tax_rate") diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 25d76aa66d..3de550c4c2 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -2,7 +2,7 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import webnotes +import webnotes, json from webnotes import _, msgprint from webnotes.utils import flt, _round @@ -280,3 +280,6 @@ class BuyingController(StockController): (", ".join((["%s"]*len(item_codes))),), item_codes)] return self._purchase_items + + def get_bin_details(self, arg): + return {"projected_qty": webnotes.conn.get_value("Bin", json.loads(arg), "projected_qty") or 0 } diff --git a/public/js/controllers/accounts.js b/public/js/controllers/accounts.js new file mode 100644 index 0000000000..201c47e2bb --- /dev/null +++ b/public/js/controllers/accounts.js @@ -0,0 +1,18 @@ + +// get tax rate +cur_frm.cscript.account_head = function(doc, cdt, cdn) { + var d = locals[cdt][cdn]; + if(!d.charge_type && d.account_head){ + msgprint("Please select Charge Type first"); + wn.model.set_value(cdt, cdn, "account_head", ""); + } else if(d.account_head && d.charge_type!=="Actual") { + wn.call({ + type:"GET", + method: "controllers.accounts_controller.get_tax_rate", + args: {"account_head":d.account_head}, + callback: function(r) { + wn.model.set_value(cdt, cdn, "rate", r.message || 0); + } + }) + } +} diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index b6bc45d772..78afb97404 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -56,13 +56,7 @@ class DocType(SellingController): # -------------------------------------------------------------- def get_adj_percent(self, arg=''): get_obj('Sales Common').get_adj_percent(self) - - # Get Tax rate if account type is TAX - # ----------------------------------- - def get_rate(self,arg): - return get_obj('Sales Common').get_rate(arg) - # Does not allow same item code to be entered twice # ------------------------------------------------- def validate_for_items(self): diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js index c87e823dba..f744faa32a 100644 --- a/selling/doctype/sales_common/sales_common.js +++ b/selling/doctype/sales_common/sales_common.js @@ -10,6 +10,7 @@ wn.provide("erpnext.selling"); wn.require("app/js/transaction.js"); +wn.require("app/js/controllers/accounts.js"); erpnext.selling.SellingController = erpnext.TransactionController.extend({ onload: function() { diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py index df7f151149..634ea2a370 100644 --- a/selling/doctype/sales_common/sales_common.py +++ b/selling/doctype/sales_common/sales_common.py @@ -86,26 +86,6 @@ class DocType(TransactionBase): if (obj.doc.price_list_currency == default_currency and flt(obj.doc.plc_conversion_rate) != 1.00) or not obj.doc.plc_conversion_rate or (obj.doc.price_list_currency != default_currency and flt(obj.doc.plc_conversion_rate) == 1.00): msgprint("Please Enter Appropriate Conversion Rate for Price List Currency to Base Currency (%s --> %s)" % (obj.doc.price_list_currency, default_currency), raise_exception = 1) - - - - # Get Tax rate if account type is TAX - # ========================================================================= - def get_rate(self, arg): - arg = eval(arg) - rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = '%s' and docstatus != 2" %(arg['account_head']), as_dict=1) - ret = {'rate' : 0} - if arg['charge_type'] == 'Actual' and rate[0]['account_type'] == 'Tax': - msgprint("You cannot select ACCOUNT HEAD of type TAX as your CHARGE TYPE is 'ACTUAL'") - ret = { - 'account_head' : '' - } - elif rate[0]['account_type'] in ['Tax', 'Chargeable'] and not arg['charge_type'] == 'Actual': - ret = { - 'rate' : rate and flt(rate[0]['tax_rate']) or 0 - } - return ret - def get_item_list(self, obj, is_stopped=0): """get item list""" diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 0cdca58ce9..1c22c08a3b 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -38,9 +38,6 @@ class DocType(SellingController): def get_available_qty(self,args): return get_obj('Sales Common').get_available_qty(eval(args)) - def get_rate(self,arg): - return get_obj('Sales Common').get_rate(arg) - def validate_mandatory(self): # validate transaction date v/s delivery date if self.doc.delivery_date: diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index b20e790af7..281908598f 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -66,9 +66,6 @@ class DocType(SellingController): """Re-calculates Basic Rate & amount based on Price List Selected""" get_obj('Sales Common').get_adj_percent(self) - def get_rate(self,arg): - return get_obj('Sales Common').get_rate(arg) - def so_required(self): """check in manage account if sales order required or not""" if webnotes.conn.get_value("Selling Settings", None, 'so_required') == 'Yes': diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py index d1672ba12c..7aea3364e4 100644 --- a/stock/doctype/material_request/material_request.py +++ b/stock/doctype/material_request/material_request.py @@ -20,10 +20,6 @@ class DocType(BuyingController): self.tname = 'Material Request Item' self.fname = 'indent_details' - # get available qty at warehouse - def get_bin_details(self, arg = ''): - return get_obj(dt='Purchase Common').get_bin_details(arg) - def check_if_already_pulled(self): pass#if self.[d.sales_order_no for d in getlist(self.doclist, 'indent_details')] diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 6169b1d916..1e1f1eaf86 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -38,10 +38,6 @@ class DocType(BuyingController): total_qty = sum((item.qty for item in self.doclist.get({"parentfield": "purchase_receipt_details"}))) self.doc.fields["__billing_complete"] = billed_qty[0][0] == total_qty - # get available qty at warehouse - def get_bin_details(self, arg = ''): - return get_obj(dt='Purchase Common').get_bin_details(arg) - def validate(self): super(DocType, self).validate() @@ -290,10 +286,6 @@ class DocType(BuyingController): bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.doc.supplier_warehouse), as_dict = 1) d.current_stock = bin and flt(bin[0]['actual_qty']) or 0 - - def get_rate(self,arg): - return get_obj('Purchase Common').get_rate(arg,self) - def get_gl_entries_for_stock(self, warehouse_account=None): against_stock_account = self.get_company_default("stock_received_but_not_billed") From 2eec1eb9a68510f708244e75879e084bf2750617 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 10 Oct 2013 17:03:56 +0530 Subject: [PATCH 100/123] [minor] removed prevdoc_date --- .../purchase_common/purchase_common.py | 7 ------- .../doctype/purchase_order/purchase_order.js | 4 ++-- .../doctype/purchase_order/purchase_order.py | 1 - .../purchase_order_item.txt | 17 +---------------- .../supplier_quotation/supplier_quotation.py | 1 - .../supplier_quotation_item.txt | 17 +---------------- controllers/buying_controller.py | 4 +--- .../installation_note/installation_note.py | 1 - .../installation_note_item.txt | 14 +------------- selling/doctype/sales_common/sales_common.py | 19 ------------------- stock/doctype/delivery_note/delivery_note.js | 4 ++-- stock/doctype/delivery_note/delivery_note.py | 2 -- .../delivery_note_item/delivery_note_item.txt | 15 +-------------- .../purchase_receipt/purchase_receipt.py | 1 - .../purchase_receipt_item.txt | 15 +-------------- 15 files changed, 10 insertions(+), 112 deletions(-) diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py index 1d57f88910..8637e5fb43 100644 --- a/buying/doctype/purchase_common/purchase_common.py +++ b/buying/doctype/purchase_common/purchase_common.py @@ -189,10 +189,3 @@ class DocType(BuyingController): if not submitted: msgprint(cstr(doctype) + ": " + cstr(submitted[0][0]) + _(" not submitted"), raise_exception=1) - - def get_prevdoc_date(self, obj): - for d in getlist(obj.doclist, obj.fname): - if d.prevdoc_doctype and d.prevdoc_docname: - dt = webnotes.conn.sql("select transaction_date from `tab%s` where name = %s" - % (d.prevdoc_doctype, '%s'), (d.prevdoc_docname)) - d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or '' \ No newline at end of file diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js index 9967f15a50..f32f11a2a6 100644 --- a/buying/doctype/purchase_order/purchase_order.js +++ b/buying/doctype/purchase_order/purchase_order.js @@ -185,9 +185,9 @@ cur_frm.pformat.indent_no = function(doc, cdt, cdn){ if(cl[i].prevdoc_doctype == 'Material Request' && cl[i].prevdoc_docname && prevdoc_list.indexOf(cl[i].prevdoc_docname) == -1) { prevdoc_list.push(cl[i].prevdoc_docname); if(prevdoc_list.length ==1) - out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, cl[i].prevdoc_date,0); + out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, null,0); else - out += make_row('', cl[i].prevdoc_docname, cl[i].prevdoc_date,0); + out += make_row('', cl[i].prevdoc_docname,null,0); } } } diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py index dc75466a4b..cf207bb747 100644 --- a/buying/doctype/purchase_order/purchase_order.py +++ b/buying/doctype/purchase_order/purchase_order.py @@ -41,7 +41,6 @@ class DocType(BuyingController): pc_obj = get_obj(dt='Purchase Common') pc_obj.validate_for_items(self) - pc_obj.get_prevdoc_date(self) self.check_for_stopped_status(pc_obj) self.validate_uom_is_integer("uom", "qty") diff --git a/buying/doctype/purchase_order_item/purchase_order_item.txt b/buying/doctype/purchase_order_item/purchase_order_item.txt index 36b81d2c1f..fade98fa98 100755 --- a/buying/doctype/purchase_order_item/purchase_order_item.txt +++ b/buying/doctype/purchase_order_item/purchase_order_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:06", "docstatus": 0, - "modified": "2013-08-07 14:44:12", + "modified": "2013-10-10 17:01:57", "modified_by": "Administrator", "owner": "Administrator" }, @@ -306,21 +306,6 @@ "search_index": 1, "width": "120px" }, - { - "doctype": "DocField", - "fieldname": "prevdoc_date", - "fieldtype": "Date", - "hidden": 1, - "in_filter": 1, - "in_list_view": 0, - "label": "Material Request Date", - "no_copy": 1, - "oldfieldname": "prevdoc_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1, - "search_index": 0 - }, { "doctype": "DocField", "fieldname": "prevdoc_detail_docname", diff --git a/buying/doctype/supplier_quotation/supplier_quotation.py b/buying/doctype/supplier_quotation/supplier_quotation.py index c3d2f78451..8c5224e30a 100644 --- a/buying/doctype/supplier_quotation/supplier_quotation.py +++ b/buying/doctype/supplier_quotation/supplier_quotation.py @@ -54,7 +54,6 @@ class DocType(BuyingController): def validate_common(self): pc = get_obj('Purchase Common') pc.validate_for_items(self) - pc.get_prevdoc_date(self) @webnotes.whitelist() def make_purchase_order(source_name, target_doclist=None): diff --git a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt index 1d162915ef..515cdb2a34 100644 --- a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt +++ b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-22 12:43:10", "docstatus": 0, - "modified": "2013-08-07 14:44:18", + "modified": "2013-10-10 17:02:11", "modified_by": "Administrator", "owner": "Administrator" }, @@ -259,21 +259,6 @@ "search_index": 1, "width": "120px" }, - { - "doctype": "DocField", - "fieldname": "prevdoc_date", - "fieldtype": "Date", - "hidden": 1, - "in_filter": 1, - "in_list_view": 0, - "label": "Material Request Date", - "no_copy": 1, - "oldfieldname": "prevdoc_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1, - "search_index": 0 - }, { "doctype": "DocField", "fieldname": "prevdoc_detail_docname", diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 3de550c4c2..2e55aee135 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -14,6 +14,7 @@ from controllers.stock_controller import StockController class WrongWarehouseCompany(Exception): pass class BuyingController(StockController): + def onload_post_render(self): # contact, address, item details self.set_missing_values() @@ -280,6 +281,3 @@ class BuyingController(StockController): (", ".join((["%s"]*len(item_codes))),), item_codes)] return self._purchase_items - - def get_bin_details(self, arg): - return {"projected_qty": webnotes.conn.get_value("Bin", json.loads(arg), "projected_qty") or 0 } diff --git a/selling/doctype/installation_note/installation_note.py b/selling/doctype/installation_note/installation_note.py index ca47043e28..02b724719c 100644 --- a/selling/doctype/installation_note/installation_note.py +++ b/selling/doctype/installation_note/installation_note.py @@ -38,7 +38,6 @@ class DocType(TransactionBase): self.check_item_table() sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_active_sales_items(self) - sales_com_obj.get_prevdoc_date(self) def validate_fiscal_year(self): from accounts.utils import validate_fiscal_year diff --git a/selling/doctype/installation_note_item/installation_note_item.txt b/selling/doctype/installation_note_item/installation_note_item.txt index 02871ad734..7435d461b4 100644 --- a/selling/doctype/installation_note_item/installation_note_item.txt +++ b/selling/doctype/installation_note_item/installation_note_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-22 01:27:51", "docstatus": 0, - "modified": "2013-07-10 14:54:09", + "modified": "2013-10-10 17:02:31", "modified_by": "Administrator", "owner": "Administrator" }, @@ -48,18 +48,6 @@ "read_only": 1, "width": "300px" }, - { - "doctype": "DocField", - "fieldname": "prevdoc_date", - "fieldtype": "Date", - "hidden": 0, - "in_list_view": 1, - "label": "Delivery Date", - "oldfieldname": "prevdoc_date", - "oldfieldtype": "Date", - "print_hide": 0, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "serial_no", diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py index 634ea2a370..01718dd3f0 100644 --- a/selling/doctype/sales_common/sales_common.py +++ b/selling/doctype/sales_common/sales_common.py @@ -298,25 +298,6 @@ class DocType(TransactionBase): exact_outstanding = flt(tot_outstanding) + flt(grand_total) get_obj('Account',acc_head[0][0]).check_credit_limit(acc_head[0][0], obj.doc.company, exact_outstanding) - def get_prevdoc_date(self, obj): - for d in getlist(obj.doclist, obj.fname): - date_field = None - - pdoctype, pname = d.prevdoc_doctype, d.prevdoc_docname - - if d.against_sales_invoice: - pdoctype, pname = "Sales Invoice", d.against_sales_invoice - elif d.against_sales_order: - pdoctype, pname = "Sales Order", d.against_sales_order - - if pdoctype and pname: - if pdoctype in ["Sales Invoice", "Delivery Note"]: - date_field = "posting_date" - else: - date_field = "transaction_date" - - d.prevdoc_date = webnotes.conn.get_value(pdoctype, pname, date_field) - def get_batch_no(doctype, txt, searchfield, start, page_len, filters): from controllers.queries import get_match_cond diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js index edfd6ff7db..29b3e47b32 100644 --- a/stock/doctype/delivery_note/delivery_note.js +++ b/stock/doctype/delivery_note/delivery_note.js @@ -184,9 +184,9 @@ cur_frm.pformat.sales_order_no= function(doc, cdt, cdn){ if(cl[i].against_sales_order && prevdoc_list.indexOf(cl[i].against_sales_order) == -1) { prevdoc_list.push(cl[i].against_sales_order); if(prevdoc_list.length ==1) - out += make_row("Sales Order", cl[i].against_sales_order, cl[i].prevdoc_date, 0); + out += make_row("Sales Order", cl[i].against_sales_order, null, 0); else - out += make_row('', cl[i].against_sales_order, cl[i].prevdoc_date,0); + out += make_row('', cl[i].against_sales_order, null,0); } } } diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 281908598f..deaf024a2e 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -86,7 +86,6 @@ class DocType(SellingController): sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) sales_com_obj.check_active_sales_items(self) - sales_com_obj.get_prevdoc_date(self) self.validate_for_items() self.validate_warehouse() self.validate_uom_is_integer("stock_uom", "qty") @@ -366,7 +365,6 @@ def make_sales_invoice(source_name, target_doclist=None): def make_installation_note(source_name, target_doclist=None): def update_item(obj, target, source_parent): target.qty = flt(obj.qty) - flt(obj.installed_qty) - target.prevdoc_date = source_parent.posting_date target.serial_no = obj.serial_no doclist = get_mapped_doclist("Delivery Note", source_name, { diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt index 4162187fdc..8d1792d7c1 100644 --- a/stock/doctype/delivery_note_item/delivery_note_item.txt +++ b/stock/doctype/delivery_note_item/delivery_note_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-22 13:15:44", "docstatus": 0, - "modified": "2013-10-03 11:09:48", + "modified": "2013-10-10 17:03:11", "modified_by": "Administrator", "owner": "Administrator" }, @@ -362,19 +362,6 @@ "label": "Against Sales Invoice", "options": "Sales Invoice" }, - { - "doctype": "DocField", - "fieldname": "prevdoc_date", - "fieldtype": "Date", - "hidden": 1, - "in_filter": 1, - "label": "Against Document Date", - "no_copy": 1, - "oldfieldname": "prevdoc_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "prevdoc_detail_docname", diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 1e1f1eaf86..2dd450febb 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -59,7 +59,6 @@ class DocType(BuyingController): pc_obj = get_obj(dt='Purchase Common') pc_obj.validate_for_items(self) - pc_obj.get_prevdoc_date(self) self.check_for_stopped_status(pc_obj) # sub-contracting diff --git a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt index ce491689ec..9c0d0fbb11 100755 --- a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt +++ b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:10", "docstatus": 0, - "modified": "2013-09-20 11:36:55", + "modified": "2013-10-10 17:02:51", "modified_by": "Administrator", "owner": "Administrator" }, @@ -424,19 +424,6 @@ "search_index": 1, "width": "150px" }, - { - "doctype": "DocField", - "fieldname": "prevdoc_date", - "fieldtype": "Date", - "hidden": 1, - "in_filter": 1, - "label": "Purchase Order Date", - "no_copy": 1, - "oldfieldname": "prevdoc_date", - "oldfieldtype": "Date", - "print_hide": 1, - "read_only": 1 - }, { "doctype": "DocField", "fieldname": "rm_supp_cost", From 9106221ea4ffc049da7bf31ca2c71531b6b248b5 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 10 Oct 2013 18:43:34 +0530 Subject: [PATCH 101/123] [minor] fixes after merge with master --- .../sales_invoice/test_sales_invoice.py | 10 ++--- .../voucher_import_tool.py | 14 +++---- .../purchase_order/test_purchase_order.py | 6 +-- controllers/buying_controller.py | 2 - .../doctype/backup_manager/backup_dropbox.py | 4 +- .../delivery_note/test_delivery_note.py | 6 +-- .../material_request/test_material_request.py | 4 +- .../purchase_receipt/purchase_receipt.py | 2 +- .../purchase_receipt/test_purchase_receipt.py | 3 +- stock/doctype/serial_no/serial_no.py | 40 +++++++++++-------- stock/doctype/stock_entry/stock_entry.py | 2 +- stock/doctype/stock_entry/test_stock_entry.py | 7 ++-- .../stock_ledger_entry/stock_ledger_entry.py | 6 +-- stock/utils.py | 18 ++++----- 14 files changed, 64 insertions(+), 60 deletions(-) diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index dee098a3e4..9f5b95cd79 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -641,8 +641,8 @@ class TestSalesInvoice(unittest.TestCase): return new_si - # if yearly, test 3 repetitions, else test 13 repetitions - count = 3 if no_of_months == 12 else 13 + # if yearly, test 1 repetition, else test 5 repetitions + count = 1 if (no_of_months == 12) else 5 for i in xrange(count): base_si = _test(i) @@ -653,7 +653,7 @@ class TestSalesInvoice(unittest.TestCase): def test_serialized(self): from stock.doctype.stock_entry.test_stock_entry import make_serialized_item - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos se = make_serialized_item() serial_nos = get_serial_nos(se.doclist[1].serial_no) @@ -674,7 +674,7 @@ class TestSalesInvoice(unittest.TestCase): return si def test_serialized_cancel(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos si = self.test_serialized() si.cancel() @@ -686,7 +686,7 @@ class TestSalesInvoice(unittest.TestCase): "delivery_document_no")) def test_serialize_status(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos + from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos from stock.doctype.stock_entry.test_stock_entry import make_serialized_item se = make_serialized_item() diff --git a/accounts/page/voucher_import_tool/voucher_import_tool.py b/accounts/page/voucher_import_tool/voucher_import_tool.py index 9425afc7d0..14e30be7a9 100644 --- a/accounts/page/voucher_import_tool/voucher_import_tool.py +++ b/accounts/page/voucher_import_tool/voucher_import_tool.py @@ -64,10 +64,10 @@ def upload(): data, start_idx = get_data(rows, company_abbr, rows[0][0]) except Exception, e: - err_msg = webnotes.message_log and "
".join(webnotes.message_log) or cstr(e) + err_msg = webnotes.local.message_log and "
".join(webnotes.local.message_log) or cstr(e) messages.append("""

%s

""" % (err_msg or "No message")) webnotes.errprint(webnotes.getTraceback()) - webnotes.message_log = [] + webnotes.local.message_log = [] return messages return import_vouchers(common_values, data, start_idx, rows[0][0]) @@ -117,11 +117,11 @@ def import_vouchers(common_values, data, start_idx, import_type): d = data[i][0] if import_type == "Voucher Import: Two Accounts" and flt(d.get("amount")) == 0: - webnotes.message_log = ["Amount not specified"] + webnotes.local.message_log = ["Amount not specified"] raise Exception elif import_type == "Voucher Import: Multiple Accounts" and \ (flt(d.get("total_debit")) == 0 or flt(d.get("total_credit")) == 0): - webnotes.message_log = ["Total Debit and Total Credit amount can not be zero"] + webnotes.local.message_log = ["Total Debit and Total Credit amount can not be zero"] raise Exception else: d.posting_date = parse_date(d.posting_date) @@ -174,7 +174,7 @@ def import_vouchers(common_values, data, start_idx, import_type): details.append(detail) if not details: - webnotes.message_log = ["""No accounts found. + webnotes.local.message_log = ["""No accounts found. If you entered accounts correctly, please check template once"""] raise Exception @@ -193,12 +193,12 @@ def import_vouchers(common_values, data, start_idx, import_type): webnotes.conn.commit() except Exception, e: webnotes.conn.rollback() - err_msg = webnotes.message_log and "
".join(webnotes.message_log) or cstr(e) + err_msg = webnotes.local.message_log and "
".join(webnotes.local.message_log) or cstr(e) messages.append("""

[row #%s] %s failed: %s

""" % ((start_idx + 1) + i, jv.name or "", err_msg or "No message")) messages.append("

All transactions rolled back

") webnotes.errprint(webnotes.getTraceback()) - webnotes.message_log = [] + webnotes.local.message_log = [] return messages diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py index cef5e4a207..e9a9c348a6 100644 --- a/buying/doctype/purchase_order/test_purchase_order.py +++ b/buying/doctype/purchase_order/test_purchase_order.py @@ -98,12 +98,12 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2) def test_warehouse_company_validation(self): - from controllers.buying_controller import WrongWarehouseCompany + from stock.utils import InvalidWarehouseCompany po = webnotes.bean(copy=test_records[0]) po.doc.company = "_Test Company 1" po.doc.conversion_rate = 0.0167 - self.assertRaises(WrongWarehouseCompany, po.insert) - + self.assertRaises(InvalidWarehouseCompany, po.insert) + def test_uom_integer_validation(self): from utilities.transaction_base import UOMMustBeIntegerError po = webnotes.bean(copy=test_records[0]) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 2e55aee135..c42eda50bc 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -11,8 +11,6 @@ from setup.utils import get_company_currency from controllers.stock_controller import StockController -class WrongWarehouseCompany(Exception): pass - class BuyingController(StockController): def onload_post_render(self): diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index b4a8f66d4c..3d3f428260 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -61,8 +61,8 @@ def dropbox_callback(oauth_token=None, not_approved=False): allowed = 0 message = "Dropbox Access not approved." - webnotes.message_title = "Dropbox Approval" - webnotes.message = "

%s

Please close this window.

" % message + webnotes.local.message_title = "Dropbox Approval" + webnotes.local.message = "

%s

Please close this window.

" % message webnotes.conn.commit() webnotes.response['type'] = 'page' diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py index 7c525504ae..ca95a50602 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -160,7 +160,7 @@ class TestDeliveryNote(unittest.TestCase): def test_serialized(self): from stock.doctype.stock_entry.test_stock_entry import make_serialized_item - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos se = make_serialized_item() serial_nos = get_serial_nos(se.doclist[1].serial_no) @@ -180,7 +180,7 @@ class TestDeliveryNote(unittest.TestCase): return dn def test_serialized_cancel(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos dn = self.test_serialized() dn.cancel() @@ -192,7 +192,7 @@ class TestDeliveryNote(unittest.TestCase): "delivery_document_no")) def test_serialize_status(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos + from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos from stock.doctype.stock_entry.test_stock_entry import make_serialized_item se = make_serialized_item() diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py index 8ebad15810..13fdd02c3c 100644 --- a/stock/doctype/material_request/test_material_request.py +++ b/stock/doctype/material_request/test_material_request.py @@ -315,10 +315,10 @@ class TestMaterialRequest(unittest.TestCase): self.assertRaises(webnotes.MappingMismatchError, se.insert) def test_warehouse_company_validation(self): - from controllers.buying_controller import WrongWarehouseCompany + from stock.utils import InvalidWarehouseCompany mr = webnotes.bean(copy=test_records[0]) mr.doc.company = "_Test Company 1" - self.assertRaises(WrongWarehouseCompany, mr.insert) + self.assertRaises(InvalidWarehouseCompany, mr.insert) test_dependencies = ["Currency Exchange"] test_records = [ diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 2dd450febb..537d75d339 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -242,7 +242,7 @@ class DocType(BuyingController): self.update_stock() from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit - update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") + update_serial_nos_after_submit(self, "purchase_receipt_details") purchase_controller.update_last_purchase_rate(self, 1) diff --git a/stock/doctype/purchase_receipt/test_purchase_receipt.py b/stock/doctype/purchase_receipt/test_purchase_receipt.py index 010c29be79..613dfbc6b0 100644 --- a/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -104,6 +104,7 @@ class TestPurchaseReceipt(unittest.TestCase): pr.doclist[1].received_qty = 1 pr.insert() pr.submit() + self.assertEquals(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no, "supplier"), pr.doc.supplier) @@ -112,7 +113,7 @@ class TestPurchaseReceipt(unittest.TestCase): def test_serial_no_cancel(self): pr = self.test_serial_no_supplier() pr.cancel() - + self.assertFalse(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no, "warehouse")) diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 93836d64e4..61b2841787 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -37,11 +37,8 @@ class DocType(StockController): self.validate_warehouse() self.validate_item() - if self.via_stock_ledger: - self.set_status() - self.set_purchase_details() - self.set_sales_details() - + self.on_stock_ledger_entry() + def validate_amc_status(self): """ validate amc status @@ -118,7 +115,7 @@ class DocType(StockController): and ifnull(is_cancelled, 'No')='No' order by name asc limit 1""", ("%%%s%%" % (self.doc.name+"\n"), "%%%s%%" % ("\n"+self.doc.name), self.doc.name, self.doc.item_code), as_dict=1) - + if purchase_sle: self.doc.purchase_document_type = purchase_sle[0].voucher_type self.doc.purchase_document_no = purchase_sle[0].voucher_no @@ -181,6 +178,12 @@ class DocType(StockController): webnotes.conn.sql("""update `tab%s` set serial_no = %s where name=%s""" % (dt[0], '%s', '%s'), ('\n'.join(serial_nos), item[0])) + + def on_stock_ledger_entry(self): + if self.via_stock_ledger and not self.doc.fields.get("__islocal"): + self.set_status() + self.set_purchase_details() + self.set_sales_details() def process_serial_no(sle): item_det = get_item_details(sle.item_code) @@ -233,6 +236,14 @@ def validate_serial_no(sle, item_det): + sle.item_code), SerialNoRequiredError) def update_serial_nos(sle, item_det): + if not sle.serial_no and sle.actual_qty > 0 and item_det.serial_no_series: + from webnotes.model.doc import make_autoname + serial_nos = [] + for i in xrange(cint(sle.actual_qty)): + serial_nos.append(make_autoname(item_det.serial_no_series)) + + webnotes.conn.set(sle, "serial_no", "\n".join(serial_nos)) + if sle.serial_no: serial_nos = get_serial_nos(sle.serial_no) for serial_no in serial_nos: @@ -243,12 +254,6 @@ def update_serial_nos(sle, item_det): sr.save() elif sle.actual_qty > 0: make_serial_no(serial_no, sle) - elif sle.actual_qty > 0 and item_det.serial_no_series: - from webnotes.model.doc import make_autoname - serial_nos = [] - for i in xrange(cint(sle.actual_qty)): - serial_nos.append(make_serial_no(make_autoname(item_det.serial_no_series), sle)) - sle.serial_no = "\n".join(serial_nos) def get_item_details(item_code): return webnotes.conn.sql("""select name, has_batch_no, docstatus, @@ -270,13 +275,16 @@ def make_serial_no(serial_no, sle): webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) return sr.doc.name -def update_serial_nos_after_submit(controller, parenttype, parentfield): - if not hasattr(webnotes, "new_stock_ledger_entries"): - return +def update_serial_nos_after_submit(controller, parentfield): + stock_ledger_entries = webnotes.conn.sql("""select voucher_detail_no, serial_no + from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""", + (controller.doc.doctype, controller.doc.name), as_dict=True) + if not stock_ledger_entries: return + for d in controller.doclist.get({"parentfield": parentfield}): serial_no = None - for sle in webnotes.new_stock_ledger_entries: + for sle in stock_ledger_entries: if sle.voucher_detail_no==d.name: serial_no = sle.serial_no break diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 0117864a1b..63cfd2be90 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -53,7 +53,7 @@ class DocType(StockController): self.update_stock_ledger() from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit - update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") + update_serial_nos_after_submit(self, "mtn_details") self.update_production_order(1) self.make_gl_entries() diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index b41a6269ad..f01a83b2f7 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -44,9 +44,10 @@ class TestStockEntry(unittest.TestCase): def test_warehouse_company_validation(self): self._clear_stock_account_balance() - webnotes.session.user = "test2@example.com" webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") + + webnotes.session.user = "test2@example.com" from stock.utils import InvalidWarehouseCompany st1 = webnotes.bean(copy=test_records[0]) @@ -59,13 +60,13 @@ class TestStockEntry(unittest.TestCase): def test_warehouse_user(self): from stock.utils import UserNotAllowedForWarehouse - webnotes.session.user = "test@example.com" webnotes.bean("Profile", "test@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - + + webnotes.session.user = "test@example.com" st1 = webnotes.bean(copy=test_records[0]) st1.doc.company = "_Test Company 1" st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 8fef889f72..c7703ed7ee 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -14,10 +14,6 @@ class DocType(DocListController): def validate(self): from stock.utils import validate_warehouse_user, validate_warehouse_company - if not hasattr(webnotes, "new_stock_ledger_entries"): - webnotes.new_stock_ledger_entries = [] - - webnotes.new_stock_ledger_entries.append(self.doc) self.validate_mandatory() self.validate_item() validate_warehouse_user(self.doc.warehouse) @@ -52,7 +48,7 @@ class DocType(DocListController): %(item_code)s at Warehouse %(warehouse)s \ as on %(posting_date)s %(posting_time)s""" % self.doc.fields) - sself.doc.fields.pop('batch_bal') + self.doc.fields.pop('batch_bal') def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] diff --git a/stock/utils.py b/stock/utils.py index 1f501644ff..95b9bffc55 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -252,10 +252,10 @@ def get_buying_amount(voucher_type, voucher_no, item_row, stock_ledger_entries): def reorder_item(): """ Reorder item if stock reaches reorder level""" - if not hasattr(webnotes, "auto_indent"): - webnotes.auto_indent = cint(webnotes.conn.get_value('Stock Settings', None, 'auto_indent')) + if getattr(webnotes.local, "auto_indent", None) is None: + webnotes.local.auto_indent = cint(webnotes.conn.get_value('Stock Settings', None, 'auto_indent')) - if webnotes.auto_indent: + if webnotes.local.auto_indent: material_requests = {} bin_list = webnotes.conn.sql("""select item_code, warehouse, projected_qty from tabBin where ifnull(item_code, '') != '' and ifnull(warehouse, '') != '' @@ -340,18 +340,18 @@ def create_material_request(material_requests): mr_list.append(mr_bean) except: - if webnotes.message_log: - exceptions_list.append([] + webnotes.message_log) - webnotes.message_log = [] + if webnotes.local.message_log: + exceptions_list.append([] + webnotes.local.message_log) + webnotes.local.message_log = [] else: exceptions_list.append(webnotes.getTraceback()) if mr_list: - if not hasattr(webnotes, "reorder_email_notify"): - webnotes.reorder_email_notify = cint(webnotes.conn.get_value('Stock Settings', None, + if getattr(webnotes.local, "reorder_email_notify", None) is None: + webnotes.local.reorder_email_notify = cint(webnotes.conn.get_value('Stock Settings', None, 'reorder_email_notify')) - if(webnotes.reorder_email_notify): + if(webnotes.local.reorder_email_notify): send_email_notification(mr_list) if exceptions_list: From 0948b2a9d3604cb7755895a204b8a5415f38aec9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:04:18 +0530 Subject: [PATCH 102/123] [fix] [minor] repost order qty patch --- patches/december_2012/repost_ordered_qty.py | 25 +++++++++++-------- patches/patch_list.py | 1 + stock/doctype/serial_no/serial_no.py | 2 +- .../stock_ledger_entry/stock_ledger_entry.py | 6 ++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py index 2e3c690adf..e73b72663d 100644 --- a/patches/december_2012/repost_ordered_qty.py +++ b/patches/december_2012/repost_ordered_qty.py @@ -4,15 +4,18 @@ def execute(): import webnotes from webnotes.utils import flt - bins = webnotes.conn.sql("select item_code, warehouse, name, ordered_qty from `tabBin`") - for d in bins: - ordered_qty = webnotes.conn.sql(""" - select sum(ifnull(po_item.qty, 0) - ifnull(po_item.received_qty, 0)) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.parent = po.name and po.docstatus = 1 and po.status != 'Stopped' - and po_item.item_code = %s and po_item.warehouse = %s - """, (d[0], d[1])) - if flt(d[3]) != flt(ordered_qty[0][0]): - webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""", - (ordered_qty and ordered_qty[0][0] or 0, d[2])) \ No newline at end of file + for d in webnotes.conn.sql("select name, item_code, warehouse, ordered_qty from tabBin", + as_dict=1): + ordered_qty = webnotes.conn.sql(""" + select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + from `tabPurchase Order Item` po_item, `tabPurchase Order` po + where po_item.item_code=%s and po_item.warehouse=%s + and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po.status!='Stopped' and po.docstatus=1""", (d.item_code, d.warehouse)) + + if flt(d.ordered_qty) != flt(ordered_qty[0][0]): + webnotes.conn.set_value("Bin", d.name, "ordered_qty", flt(ordered_qty[0][0])) + + webnotes.conn.sql("""update tabBin set projected_qty = actual_qty + planned_qty + + indented_qty + ordered_qty - reserved_qty where name = %s""", d.name) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index f228acf97e..6a5d0f4f55 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -220,4 +220,5 @@ patch_list = [ "patches.september_2013.p04_unsubmit_serial_nos", "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", + "patches.october_2013.repost_ordered_qty", ] \ No newline at end of file diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index 3922878280..d806287ecb 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cint, getdate, nowdate, cstr, flt, add_days +from webnotes.utils import cint, getdate, cstr, flt, add_days import datetime from webnotes import msgprint, _, ValidationError diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 8fef889f72..bfb0f0aa92 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import _, msgprint -from webnotes.utils import cint, flt, getdate, cstr +from webnotes import msgprint +from webnotes.utils import flt, getdate from webnotes.model.controller import DocListController class DocType(DocListController): @@ -52,7 +52,7 @@ class DocType(DocListController): %(item_code)s at Warehouse %(warehouse)s \ as on %(posting_date)s %(posting_time)s""" % self.doc.fields) - sself.doc.fields.pop('batch_bal') + self.doc.fields.pop('batch_bal') def validate_mandatory(self): mandatory = ['warehouse','posting_date','voucher_type','voucher_no','actual_qty','company'] From 2658384edd45051d190dc902ffa523288bff4f50 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:07:42 +0530 Subject: [PATCH 103/123] [fix] [minor] repost order qty patch --- patches/october_2013/repost_ordered_qty.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 patches/october_2013/repost_ordered_qty.py diff --git a/patches/october_2013/repost_ordered_qty.py b/patches/october_2013/repost_ordered_qty.py new file mode 100644 index 0000000000..55827941b0 --- /dev/null +++ b/patches/october_2013/repost_ordered_qty.py @@ -0,0 +1,6 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +def execute(): + from patches.december_2012 import repost_ordered_qty + repost_ordered_qty.execute() \ No newline at end of file From 93c836c86dbe2b0f860addfed50dda485b5ab742 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 10 Oct 2013 19:15:58 +0530 Subject: [PATCH 104/123] [fix] [minor] validate warehouse user --- stock/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock/utils.py b/stock/utils.py index 1f501644ff..983ee72c05 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -209,7 +209,7 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): return wlist def validate_warehouse_user(warehouse): - if webnotes.session.user=="Administrator": + if webnotes.session.user=="Administrator" or not warehouse: return warehouse_users = [p[0] for p in webnotes.conn.sql("""select user from `tabWarehouse User` where parent=%s""", warehouse)] From 915eda9c4ad2852bbb01d2970ae12baf67dce2f8 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 11 Oct 2013 10:56:49 +0530 Subject: [PATCH 105/123] [minor] Added allow_rename in Employee webnotes/erpnetx#962 --- hr/doctype/employee/employee.txt | 3 ++- portal/templates/pages/cart.py | 3 ++- portal/templates/pages/profile.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hr/doctype/employee/employee.txt b/hr/doctype/employee/employee.txt index bbe87ad880..4ed873275a 100644 --- a/hr/doctype/employee/employee.txt +++ b/hr/doctype/employee/employee.txt @@ -2,12 +2,13 @@ { "creation": "2013-03-07 09:04:18", "docstatus": 0, - "modified": "2013-08-08 14:22:11", + "modified": "2013-10-11 10:52:53", "modified_by": "Administrator", "owner": "Administrator" }, { "allow_attach": 1, + "allow_rename": 1, "autoname": "naming_series:", "doctype": "DocType", "document_type": "Master", diff --git a/portal/templates/pages/cart.py b/portal/templates/pages/cart.py index 24b474a55c..ecf3163f0a 100644 --- a/portal/templates/pages/cart.py +++ b/portal/templates/pages/cart.py @@ -3,4 +3,5 @@ from __future__ import unicode_literals -no_cache = True \ No newline at end of file +no_cache = True +no_sitemap = True \ No newline at end of file diff --git a/portal/templates/pages/profile.py b/portal/templates/pages/profile.py index 3d6a86f9cc..3a75cfb082 100644 --- a/portal/templates/pages/profile.py +++ b/portal/templates/pages/profile.py @@ -7,6 +7,7 @@ from webnotes import _ from webnotes.utils import cstr no_cache = True +no_sitemap = True def get_context(): from selling.utils.cart import get_lead_or_customer From 1797cfef634c6b154dc10fe192d1ebc444509ee4 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 11 Oct 2013 13:34:10 +0530 Subject: [PATCH 106/123] [fix] removed validation of conversion rate equals 1 from all transaction --- .../doctype/sales_invoice/sales_invoice.txt | 3 +- public/js/transaction.js | 39 ++++--------------- selling/doctype/quotation/quotation.txt | 3 +- selling/doctype/sales_order/sales_order.txt | 3 +- stock/doctype/delivery_note/delivery_note.txt | 5 +-- .../purchase_receipt/purchase_receipt.txt | 3 +- utilities/transaction_base.py | 9 +---- 7 files changed, 15 insertions(+), 50 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index 516d1925a8..b168ba64fd 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-10-03 18:54:31", + "modified": "2013-10-11 13:12:38", "modified_by": "Administrator", "owner": "Administrator" }, @@ -225,7 +225,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which Customer Currency is converted to customer's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/public/js/transaction.js b/public/js/transaction.js index e12d1084e9..a7be5bdbf5 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -21,8 +21,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: wn.defaults.get_default("company"), fiscal_year: wn.defaults.get_default("fiscal_year"), is_subcontracted: "No", - conversion_rate: 1.0, - plc_conversion_rate: 1.0 }, function(fieldname, value) { if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) me.frm.set_value(fieldname, value); @@ -131,10 +129,16 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: function() { if(this.frm.doc.company && this.frm.fields_dict.currency) { + var company_currency = this.get_company_currency(); if(!this.frm.doc.currency) { - this.frm.set_value("currency", this.get_company_currency()); + this.frm.set_value("currency", company_currency); } + if(this.frm.doc.currency == company_currency) + this.frm.set_value("conversion_rate", 1.0); + if(this.frm.doc.price_list_currency == company_currency) + this.frm.set_value('plc_conversion_rate', 1.0); + this.frm.script_manager.trigger("currency"); } }, @@ -233,29 +237,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.calculate_taxes_and_totals(); }, - // serial_no: function(doc, cdt, cdn) { - // var me = this; - // var item = wn.model.get_doc(cdt, cdn); - // if (!item.item_code) { - // wn.call({ - // method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no', - // args: {serial_no: this.serial_no.$input.val()}, - // callback: function(r) { - // if (r.message) { - // var item_code = r.message[0].item_code; - // var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item", - // this.frm.cscript.fname); - // child.item_code = item_code; - // me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name); - // } - // else - // msgprint(wn._("Invalid Serial No.")); - // me.refresh(); - // } - // }); - // } - // }, - row_id: function(doc, cdt, cdn) { var tax = wn.model.get_doc(cdt, cdn); try { @@ -486,12 +467,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } var company_currency = this.get_company_currency(); - var valid_conversion_rate = this.frm.doc.conversion_rate ? - ((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) || - (this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) : - false; - if(!valid_conversion_rate) { + if(!this.frm.doc.conversion_rate) { wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + " 1 " + this.frm.doc.currency + " = [?] " + company_currency); } diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt index 3f97c980bc..62c36b432f 100644 --- a/selling/doctype/quotation/quotation.txt +++ b/selling/doctype/quotation/quotation.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:08", "docstatus": 0, - "modified": "2013-09-10 10:46:33", + "modified": "2013-10-11 13:21:07", "modified_by": "Administrator", "owner": "Administrator" }, @@ -257,7 +257,6 @@ "width": "100px" }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt index 94e63888e3..46a06b5bc4 100644 --- a/selling/doctype/sales_order/sales_order.txt +++ b/selling/doctype/sales_order/sales_order.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-18 12:39:59", "docstatus": 0, - "modified": "2013-08-09 14:46:17", + "modified": "2013-10-11 13:18:47", "modified_by": "Administrator", "owner": "Administrator" }, @@ -272,7 +272,6 @@ "width": "100px" }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/stock/doctype/delivery_note/delivery_note.txt b/stock/doctype/delivery_note/delivery_note.txt index f1493bb3bf..6834365b3f 100644 --- a/stock/doctype/delivery_note/delivery_note.txt +++ b/stock/doctype/delivery_note/delivery_note.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:09", "docstatus": 0, - "modified": "2013-08-09 14:46:32", + "modified": "2013-10-11 13:19:40", "modified_by": "Administrator", "owner": "Administrator" }, @@ -230,7 +230,7 @@ "depends_on": "eval:doc.po_no", "doctype": "DocField", "fieldname": "po_date", - "fieldtype": "Data", + "fieldtype": "Date", "hidden": 1, "label": "Customer's Purchase Order Date", "no_copy": 0, @@ -263,7 +263,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which customer's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/stock/doctype/purchase_receipt/purchase_receipt.txt b/stock/doctype/purchase_receipt/purchase_receipt.txt index 11846435ce..f228a147c3 100755 --- a/stock/doctype/purchase_receipt/purchase_receipt.txt +++ b/stock/doctype/purchase_receipt/purchase_receipt.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-21 16:16:39", "docstatus": 0, - "modified": "2013-08-09 14:47:05", + "modified": "2013-10-11 13:20:13", "modified_by": "Administrator", "owner": "Administrator" }, @@ -215,7 +215,6 @@ "reqd": 1 }, { - "default": "1.00", "description": "Rate at which supplier's currency is converted to company's base currency", "doctype": "DocField", "fieldname": "conversion_rate", diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 36231bf4f1..9921910a8a 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -432,14 +432,7 @@ def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, c company_currency = webnotes.conn.get_value("Company", company, "default_currency") - # parenthesis for 'OR' are necessary as we want it to evaluate as - # mandatory valid condition and (1st optional valid condition - # or 2nd optional valid condition) - valid_conversion_rate = (conversion_rate and - ((currency == company_currency and conversion_rate == 1.00) - or (currency != company_currency and conversion_rate != 1.00))) - - if not valid_conversion_rate: + if not conversion_rate: msgprint(_('Please enter valid ') + conversion_rate_label + (': ') + ("1 %s = [?] %s" % (currency, company_currency)), raise_exception=True) From 56bc5c0ea68195109e4576a96a31255de11c5c03 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 11 Oct 2013 14:34:46 +0530 Subject: [PATCH 107/123] [material request] Added feature to pull items from BOM --- manufacturing/doctype/bom/bom.py | 51 ++++++++++++++- manufacturing/doctype/bom/test_bom.py | 56 +++++++++++++++- stock/doctype/item/test_item.py | 27 +++++++- .../material_request/material_request.js | 53 ++++++++++++++- .../material_request_item.txt | 4 +- stock/doctype/stock_entry/stock_entry.py | 64 ++----------------- stock/doctype/stock_entry/test_stock_entry.py | 3 - 7 files changed, 188 insertions(+), 70 deletions(-) diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 20c1141093..5954475376 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -402,4 +402,53 @@ class DocType: if act_pbom and act_pbom[0][0]: action = self.doc.docstatus < 2 and _("deactivate") or _("cancel") msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"), - raise_exception=1) \ No newline at end of file + raise_exception=1) + +def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1): + item_dict = {} + + query = """select + bom_item.item_code, + ifnull(sum(bom_item.qty_consumed_per_unit),0) * %(qty)s as qty, + item.description, + item.stock_uom, + item.default_warehouse + from + `tab%(table)s` bom_item, `tabItem` item + where + bom_item.docstatus < 2 + and bom_item.parent = "%(bom)s" + and item.name = bom_item.item_code + %(conditions)s + group by item_code, stock_uom""" + + if fetch_exploded: + items = webnotes.conn.sql(query % { + "qty": qty, + "table": "BOM Explosion Item", + "bom": bom, + "conditions": """and ifnull(item.is_pro_applicable, 'No') = 'No' + and ifnull(item.is_sub_contracted_item, 'No') = 'No' """ + }, as_dict=True) + else: + items = webnotes.conn.sql(query % { + "qty": qty, + "table": "BOM Item", + "bom": bom, + "conditions": "" + }, as_dict=True) + + # make unique + for item in items: + if item_dict.has_key(item.item_code): + item_dict[item.item_code]["qty"] += flt(item.qty) + else: + item_dict[item.item_code] = item + + return item_dict + +@webnotes.whitelist() +def get_bom_items(bom, qty=1, fetch_exploded=1): + items = get_bom_items_as_dict(bom, qty, fetch_exploded).values() + items.sort(lambda a, b: a.item_code > b.item_code and 1 or -1) + return items \ No newline at end of file diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py index d0b394a1f8..da98faf8f4 100644 --- a/manufacturing/doctype/bom/test_bom.py +++ b/manufacturing/doctype/bom/test_bom.py @@ -7,6 +7,35 @@ import unittest import webnotes test_records = [ + [ + { + "doctype": "BOM", + "item": "_Test Item Home Desktop 100", + "quantity": 1.0, + "is_active": 1, + "is_default": 1, + "docstatus": 1 + }, + { + "doctype": "BOM Item", + "item_code": "_Test Serialized Item With Series", + "parentfield": "bom_materials", + "qty": 1.0, + "rate": 5000.0, + "amount": 5000.0, + "stock_uom": "_Test UOM" + }, + { + "doctype": "BOM Item", + "item_code": "_Test Item 2", + "parentfield": "bom_materials", + "qty": 2.0, + "rate": 1000.0, + "amount": 2000.0, + "stock_uom": "_Test UOM" + } + ], + [ { "doctype": "BOM", @@ -29,10 +58,33 @@ test_records = [ "doctype": "BOM Item", "item_code": "_Test Item Home Desktop 100", "parentfield": "bom_materials", + "bom_no": "BOM/_Test Item Home Desktop 100/001", "qty": 2.0, "rate": 1000.0, "amount": 2000.0, "stock_uom": "_Test UOM" } - ] -] \ No newline at end of file + ], +] + +class TestBOM(unittest.TestCase): + def test_get_items(self): + from manufacturing.doctype.bom.bom import get_bom_items_as_dict + items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=0) + self.assertTrue(test_records[1][1]["item_code"] in items_dict) + self.assertTrue(test_records[1][2]["item_code"] in items_dict) + self.assertEquals(len(items_dict.values()), 2) + + def test_get_items_exploded(self): + from manufacturing.doctype.bom.bom import get_bom_items_as_dict + items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1) + self.assertTrue(test_records[1][1]["item_code"] in items_dict) + self.assertFalse(test_records[1][2]["item_code"] in items_dict) + self.assertTrue(test_records[0][1]["item_code"] in items_dict) + self.assertTrue(test_records[0][2]["item_code"] in items_dict) + self.assertEquals(len(items_dict.values()), 3) + + def test_get_items_list(self): + from manufacturing.doctype.bom.bom import get_bom_items + self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1)), 3) + diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index 12bb4e0578..ad88c8cc8f 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -31,7 +31,7 @@ test_records = [ "is_sales_item": "Yes", "is_service_item": "No", "inspection_required": "No", - "is_pro_applicable": "No", + "is_pro_applicable": "Yes", "is_sub_contracted_item": "No", "stock_uom": "_Test UOM", "default_income_account": "Sales - _TC", @@ -45,6 +45,26 @@ test_records = [ "material_request_type": "Purchase" }, ], + [{ + "doctype": "Item", + "item_code": "_Test Item 2", + "item_name": "_Test Item 2", + "description": "_Test Item 2", + "item_group": "_Test Item Group", + "is_stock_item": "Yes", + "is_asset_item": "No", + "has_batch_no": "No", + "has_serial_no": "No", + "is_purchase_item": "Yes", + "is_sales_item": "Yes", + "is_service_item": "No", + "inspection_required": "No", + "is_pro_applicable": "Yes", + "is_sub_contracted_item": "No", + "stock_uom": "_Test UOM", + "default_income_account": "Sales - _TC", + "default_warehouse": "_Test Warehouse - _TC", + }], [{ "doctype": "Item", "item_code": "_Test Item Home Desktop 100", @@ -61,8 +81,9 @@ test_records = [ "is_sales_item": "Yes", "is_service_item": "No", "inspection_required": "No", - "is_pro_applicable": "No", + "is_pro_applicable": "Yes", "is_sub_contracted_item": "No", + "is_manufactured_item": "Yes", "stock_uom": "_Test UOM" }, { @@ -182,7 +203,7 @@ test_records = [ "is_sales_item": "Yes", "is_service_item": "No", "inspection_required": "No", - "is_pro_applicable": "No", + "is_pro_applicable": "Yes", "is_sub_contracted_item": "No", "stock_uom": "_Test UOM" }], diff --git a/stock/doctype/material_request/material_request.js b/stock/doctype/material_request/material_request.js index 6931181dba..99e8afb0a1 100644 --- a/stock/doctype/material_request/material_request.js +++ b/stock/doctype/material_request/material_request.js @@ -21,7 +21,11 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten + wn._("Fulfilled"), cint(doc.per_ordered)); } - if(doc.docstatus == 1 && doc.status != 'Stopped'){ + if(doc.docstatus==0) { + cur_frm.add_custom_button(wn._("Get Items from BOM"), cur_frm.cscript.get_items_from_bom, "icon-sitemap"); + } + + if(doc.docstatus == 1 && doc.status != 'Stopped') { if(doc.material_request_type === "Purchase") cur_frm.add_custom_button("Make Supplier Quotation", this.make_supplier_quotation); @@ -63,6 +67,53 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten }, + schedule_date: function(doc, cdt, cdn) { + var val = locals[cdt][cdn].schedule_date; + if(val) { + $.each(wn.model.get("Material Request Item", { parent: cur_frm.doc.name }), function(i, d) { + if(!d.schedule_date) { + d.schedule_date = val; + } + }); + refresh_field("indent_details"); + } + }, + + get_items_from_bom: function() { + var d = new wn.ui.Dialog({ + title: wn._("Get Items from BOM"), + fields: [ + {"fieldname":"bom", "fieldtype":"Link", "label":wn._("BOM"), + options:"BOM"}, + {"fieldname":"fetch_exploded", "fieldtype":"Check", + "label":wn._("Fetch exploded BOM (including sub-assemblies)"), "default":1}, + {fieldname:"fetch", "label":wn._("Get Items from BOM"), "fieldtype":"Button"} + ] + }); + d.get_input("fetch").on("click", function() { + var values = d.get_values(); + if(!values) return; + + wn.call({ + method:"manufacturing.doctype.bom.bom.get_bom_items", + args: values, + callback: function(r) { + $.each(r.message, function(i, item) { + var d = wn.model.add_child(cur_frm.doc, "Material Request Item", "indent_details"); + d.item_code = item.item_code; + d.description = item.description; + d.warehouse = item.default_warehouse; + d.uom = item.stock_uom; + d.qty = item.qty; + }); + d.hide(); + refresh_field("indent_details"); + } + }); + }); + d.show(); + }, + tc_name: function() { this.get_terms(); }, diff --git a/stock/doctype/material_request_item/material_request_item.txt b/stock/doctype/material_request_item/material_request_item.txt index dae97e0929..2ef4acd531 100644 --- a/stock/doctype/material_request_item/material_request_item.txt +++ b/stock/doctype/material_request_item/material_request_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-22 01:28:02", "docstatus": 0, - "modified": "2013-08-07 14:45:11", + "modified": "2013-10-11 14:21:32", "modified_by": "Administrator", "owner": "Administrator" }, @@ -138,7 +138,7 @@ "oldfieldname": "item_name", "oldfieldtype": "Data", "print_width": "100px", - "reqd": 1, + "reqd": 0, "search_index": 1, "width": "100px" }, diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 63cfd2be90..78a0bd2812 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -472,68 +472,16 @@ class DocType(StockController): self.get_stock_and_rate() def get_bom_raw_materials(self, qty): - """ - get all items from flat bom except - child items of sub-contracted and sub assembly items - and sub assembly items itself. - """ + from manufacturing.doctype.bom.bom import get_bom_items_as_dict + # item dict = { item_code: {qty, description, stock_uom} } - item_dict = {} + item_dict = get_bom_items_as_dict(self.doc.bom_no, qty=qty, fetch_exploded = self.doc.use_multi_level_bom) - def _make_items_dict(items_list): - """makes dict of unique items with it's qty""" - for item in items_list: - if item_dict.has_key(item.item_code): - item_dict[item.item_code]["qty"] += flt(item.qty) - else: - item_dict[item.item_code] = { - "qty": flt(item.qty), - "description": item.description, - "stock_uom": item.stock_uom, - "from_warehouse": item.default_warehouse - } - - if self.doc.use_multi_level_bom: - # get all raw materials with sub assembly childs - fl_bom_sa_child_item = webnotes.conn.sql("""select - fb.item_code, - ifnull(sum(fb.qty_consumed_per_unit),0)*%s as qty, - fb.description, - fb.stock_uom, - it.default_warehouse - from - `tabBOM Explosion Item` fb,`tabItem` it - where - it.name = fb.item_code - and ifnull(it.is_pro_applicable, 'No') = 'No' - and ifnull(it.is_sub_contracted_item, 'No') = 'No' - and fb.docstatus < 2 - and fb.parent=%s group by item_code, stock_uom""", - (qty, self.doc.bom_no), as_dict=1) - - if fl_bom_sa_child_item: - _make_items_dict(fl_bom_sa_child_item) - else: - # get only BOM items - fl_bom_sa_items = webnotes.conn.sql("""select - `tabItem`.item_code, - ifnull(sum(`tabBOM Item`.qty_consumed_per_unit), 0) *%s as qty, - `tabItem`.description, - `tabItem`.stock_uom, - `tabItem`.default_warehouse - from - `tabBOM Item`, `tabItem` - where - `tabBOM Item`.parent = %s and - `tabBOM Item`.item_code = tabItem.name and - `tabBOM Item`.docstatus < 2 - group by item_code""", (qty, self.doc.bom_no), as_dict=1) - - if fl_bom_sa_items: - _make_items_dict(fl_bom_sa_items) + for item in item_dict.values(): + item.from_warehouse = item.default_warehouse return item_dict - + def get_pending_raw_materials(self, pro_obj): """ issue (item quantity) that is pending to issue or desire to transfer, diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index f01a83b2f7..4b36e5828c 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -1,9 +1,6 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. # License: GNU General Public License v3. See license.txt -# ERPNext - web based ERP (http://erpnext.com) -# For license information, please see license.txt - from __future__ import unicode_literals import webnotes, unittest from webnotes.utils import flt From eea2b34f4b69cdcdff269933de4ae76c5d859156 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 11 Oct 2013 18:31:33 +0530 Subject: [PATCH 108/123] [production] update planned and produced ty --- .../production_order/production_order.py | 11 +- .../production_order/test_production_order.py | 75 +++++++++++ patches/december_2012/repost_ordered_qty.py | 20 +-- patches/february_2013/repost_reserved_qty.py | 56 +-------- patches/october_2013/repost_planned_qty.py | 11 ++ patches/patch_list.py | 1 + stock/doctype/stock_entry/stock_entry.py | 78 +++++++----- stock/doctype/warehouse/warehouse.py | 93 +------------- stock/utils.py | 11 +- utilities/repost_stock.py | 119 ++++++++++++++++++ 10 files changed, 268 insertions(+), 207 deletions(-) create mode 100644 manufacturing/doctype/production_order/test_production_order.py create mode 100644 patches/october_2013/repost_planned_qty.py create mode 100644 utilities/repost_stock.py diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 719d149e64..b29b0f1e72 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -18,6 +18,9 @@ class DocType: self.doclist = doclist def validate(self): + if self.doc.docstatus == 0: + self.doc.status = "Draft" + import utilities utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped", "In Process", "Completed", "Cancelled"]) @@ -149,12 +152,6 @@ def get_item_details(item): @webnotes.whitelist() def make_stock_entry(production_order_id, purpose): production_order = webnotes.bean("Production Order", production_order_id) - - # validate already existing - ste = webnotes.conn.get_value("Stock Entry", { - "production_order":production_order_id, - "purpose": purpose - }, "name") stock_entry = webnotes.new_bean("Stock Entry") stock_entry.doc.purpose = purpose @@ -171,4 +168,4 @@ def make_stock_entry(production_order_id, purpose): stock_entry.doc.to_warehouse = production_order.doc.fg_warehouse stock_entry.run_method("get_items") - return [d.fields for d in stock_entry.doclist] + return [d.fields for d in stock_entry.doclist] \ No newline at end of file diff --git a/manufacturing/doctype/production_order/test_production_order.py b/manufacturing/doctype/production_order/test_production_order.py new file mode 100644 index 0000000000..9a75762ba4 --- /dev/null +++ b/manufacturing/doctype/production_order/test_production_order.py @@ -0,0 +1,75 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + + +from __future__ import unicode_literals +import unittest +import webnotes +from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory +from manufacturing.doctype.production_order.production_order import make_stock_entry + + +class TestProductionOrder(unittest.TestCase): + def test_planned_qty(self): + set_perpetual_inventory(0) + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("""delete from `tabBin`""") + webnotes.conn.sql("""delete from `tabGL Entry`""") + + pro_bean = webnotes.bean(copy = test_records[0]) + pro_bean.insert() + pro_bean.submit() + + from stock.doctype.stock_entry.test_stock_entry import test_records as se_test_records + mr1 = webnotes.bean(copy = se_test_records[0]) + mr1.insert() + mr1.submit() + + mr2 = webnotes.bean(copy = se_test_records[0]) + mr2.doclist[1].item_code = "_Test Item Home Desktop 100" + mr2.insert() + mr2.submit() + + stock_entry = make_stock_entry(pro_bean.doc.name, "Manufacture/Repack") + stock_entry = webnotes.bean(stock_entry) + + stock_entry.doc.fg_completed_qty = 4 + stock_entry.run_method("get_items") + stock_entry.submit() + + self.assertEqual(webnotes.conn.get_value("Production Order", pro_bean.doc.name, + "produced_qty"), 4) + self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test FG Item", + "warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6) + + return pro_bean.doc.name + + def test_over_production(self): + from stock.doctype.stock_entry.stock_entry import StockOverProductionError + pro_order = self.test_planned_qty() + + stock_entry = make_stock_entry(pro_order, "Manufacture/Repack") + stock_entry = webnotes.bean(stock_entry) + + stock_entry.doc.fg_completed_qty = 15 + stock_entry.run_method("get_items") + stock_entry.insert() + + self.assertRaises(StockOverProductionError, stock_entry.submit) + + + +test_records = [ + [ + { + "bom_no": "BOM/_Test FG Item/001", + "company": "_Test Company", + "doctype": "Production Order", + "production_item": "_Test FG Item", + "qty": 10.0, + "fg_warehouse": "_Test Warehouse 1 - _TC", + "wip_warehouse": "_Test Warehouse - _TC", + "stock_uom": "Nos" + } + ] +] \ No newline at end of file diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py index e73b72663d..4c1d11d39b 100644 --- a/patches/december_2012/repost_ordered_qty.py +++ b/patches/december_2012/repost_ordered_qty.py @@ -3,19 +3,9 @@ def execute(): import webnotes - from webnotes.utils import flt - - for d in webnotes.conn.sql("select name, item_code, warehouse, ordered_qty from tabBin", - as_dict=1): - ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""", (d.item_code, d.warehouse)) + from utilities.repost_stock import get_ordered_qty, update_bin - if flt(d.ordered_qty) != flt(ordered_qty[0][0]): - webnotes.conn.set_value("Bin", d.name, "ordered_qty", flt(ordered_qty[0][0])) - - webnotes.conn.sql("""update tabBin set projected_qty = actual_qty + planned_qty + - indented_qty + ordered_qty - reserved_qty where name = %s""", d.name) \ No newline at end of file + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "ordered_qty": get_ordered_qty(d[0], d[1]) + }) \ No newline at end of file diff --git a/patches/february_2013/repost_reserved_qty.py b/patches/february_2013/repost_reserved_qty.py index 3a3353f918..5c41266c2a 100644 --- a/patches/february_2013/repost_reserved_qty.py +++ b/patches/february_2013/repost_reserved_qty.py @@ -4,54 +4,10 @@ import webnotes def execute(): webnotes.conn.auto_commit_on_many_writes = 1 - repost_reserved_qty() - webnotes.conn.auto_commit_on_many_writes = 0 + from utilities.repost_stock import get_reserved_qty, update_bin -def repost_reserved_qty(): - from webnotes.utils import flt - bins = webnotes.conn.sql("select item_code, warehouse, name, reserved_qty from `tabBin`") - i = 0 - for d in bins: - i += 1 - reserved_qty = webnotes.conn.sql(""" - select - sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) - from - ( - (select - qty as dnpi_qty, - ( - select qty from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_qty, - ( - select ifnull(delivered_qty, 0) from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_delivered_qty, - parent, name - from - ( - select qty, parent_detail_docname, parent, name - from `tabDelivery Note Packing Item` dnpi_in - where item_code = %s and warehouse = %s - and parenttype="Sales Order" - and item_code != parent_item - and exists (select * from `tabSales Order` so - where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') - ) dnpi) - union - (select qty as dnpi_qty, qty as so_item_qty, - ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name - from `tabSales Order Item` so_item - where item_code = %s and reserved_warehouse = %s - and exists(select * from `tabSales Order` so - where so.name = so_item.parent and so.docstatus = 1 - and so.status != 'Stopped')) - ) tab - where - so_item_qty >= so_item_delivered_qty - """, (d[0], d[1], d[0], d[1])) - - if flt(d[3]) != flt(reserved_qty[0][0]): - webnotes.conn.sql("""update `tabBin` set reserved_qty = %s where name = %s""", - (reserved_qty and reserved_qty[0][0] or 0, d[2])) \ No newline at end of file + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "reserved_qty": get_reserved_qty(d[0], d[1]) + }) + webnotes.conn.auto_commit_on_many_writes = 0 \ No newline at end of file diff --git a/patches/october_2013/repost_planned_qty.py b/patches/october_2013/repost_planned_qty.py new file mode 100644 index 0000000000..cfe47ca115 --- /dev/null +++ b/patches/october_2013/repost_planned_qty.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +def execute(): + import webnotes + from utilities.repost_stock import get_planned_qty, update_bin + + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + update_bin(d[0], d[1], { + "planned_qty": get_planned_qty(d[0], d[1]) + }) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 6a5d0f4f55..59e0b0cf87 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -221,4 +221,5 @@ patch_list = [ "patches.september_2013.p05_fix_customer_in_pos", "patches.october_2013.fix_is_cancelled_in_sle", "patches.october_2013.repost_ordered_qty", + "patches.october_2013.repost_planned_qty", ] \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 8d2e76490c..7d8130cc85 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -6,7 +6,7 @@ import webnotes import webnotes.defaults from webnotes.utils import cstr, cint, flt, comma_or, nowdate -from webnotes.model.doc import Document, addchild +from webnotes.model.doc import addchild from webnotes.model.bean import getlist from webnotes.model.code import get_obj from webnotes import msgprint, _ @@ -21,6 +21,7 @@ class NotUpdateStockError(webnotes.ValidationError): pass class StockOverReturnError(webnotes.ValidationError): pass class IncorrectValuationRateError(webnotes.ValidationError): pass class DuplicateEntryForProductionOrderError(webnotes.ValidationError): pass +class StockOverProductionError(webnotes.ValidationError): pass from controllers.stock_controller import StockController @@ -56,12 +57,12 @@ class DocType(StockController): from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") - self.update_production_order(1) + self.update_production_order() self.make_gl_entries() def on_cancel(self): self.update_stock_ledger() - self.update_production_order(0) + self.update_production_order() self.make_cancel_gl_entries() def validate_fiscal_year(self): @@ -326,37 +327,44 @@ class DocType(StockController): self.make_sl_entries(sl_entries, self.doc.amended_from and 'Yes' or 'No') - def update_production_order(self, is_submit): + def update_production_order(self): + def _validate_production_order(pro_bean): + if flt(pro_bean.doc.docstatus) != 1: + webnotes.throw(_("Production Order must be submitted") + ": " + + self.doc.production_order) + + if pro_bean.doc.status == 'Stopped': + msgprint(_("Transaction not allowed against stopped Production Order") + ": " + + self.doc.production_order) + if self.doc.production_order: - # first perform some validations - # (they are here coz this fn is also called during on_cancel) - pro_obj = get_obj("Production Order", self.doc.production_order) - if flt(pro_obj.doc.docstatus) != 1: - msgprint("""You cannot do any transaction against - Production Order : %s, as it's not submitted""" - % (pro_obj.doc.name), raise_exception=1) - - if pro_obj.doc.status == 'Stopped': - msgprint("""You cannot do any transaction against Production Order : %s, - as it's status is 'Stopped'"""% (pro_obj.doc.name), raise_exception=1) - - # update bin - if self.doc.purpose == "Manufacture/Repack": - from stock.utils import update_bin - pro_obj.doc.produced_qty = flt(pro_obj.doc.produced_qty) + \ - (is_submit and 1 or -1 ) * flt(self.doc.fg_completed_qty) - args = { - "item_code": pro_obj.doc.production_item, - "warehouse": pro_obj.doc.fg_warehouse, - "posting_date": self.doc.posting_date, - "planned_qty": (is_submit and -1 or 1 ) * flt(self.doc.fg_completed_qty) - } - update_bin(args) + pro_bean = webnotes.bean("Production Order", self.doc.production_order) + _validate_production_order(pro_bean) + self.update_produced_qty(pro_bean) + self.update_planned_qty(pro_bean) - # update production order status - pro_obj.doc.status = (flt(pro_obj.doc.qty)==flt(pro_obj.doc.produced_qty)) \ - and 'Completed' or 'In Process' - pro_obj.doc.save() + def update_produced_qty(self, pro_bean): + if self.doc.purpose == "Manufacture/Repack": + produced_qty = flt(pro_bean.doc.produced_qty) + \ + (self.doc.docstatus==1 and 1 or -1 ) * flt(self.doc.fg_completed_qty) + + if produced_qty > flt(pro_bean.doc.qty): + webnotes.throw(_("Production Order") + ": " + self.doc.production_order + "\n" + + _("Total Manufactured Qty can not be greater than Planned qty to manufacture") + + "(%s/%s)" % (produced_qty, flt(pro_bean.doc.qty)), StockOverProductionError) + + status = 'Completed' if flt(produced_qty) >= flt(pro_bean.doc.qty) else 'In Process' + webnotes.conn.sql("""update `tabProduction Order` set status=%s, produced_qty=%s + where name=%s""", (status, produced_qty, self.doc.production_order)) + + def update_planned_qty(self, pro_bean): + from stock.utils import update_bin + update_bin({ + "item_code": pro_bean.doc.production_item, + "warehouse": pro_bean.doc.fg_warehouse, + "posting_date": self.doc.posting_date, + "planned_qty": (self.doc.docstatus==1 and -1 or 1 ) * flt(self.doc.fg_completed_qty) + }) def get_item_details(self, arg): arg = json.loads(arg) @@ -415,7 +423,8 @@ class DocType(StockController): return ret def get_items(self): - self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1) + self.doclist = filter(lambda d: d.parentfield!="mtn_details", self.doclist) + # self.doclist = self.doc.clear_table(self.doclist, 'mtn_details') pro_obj = None if self.doc.production_order: @@ -454,7 +463,7 @@ class DocType(StockController): "stock_uom": pro_obj.doc.stock_uom } }, bom_no=pro_obj.doc.bom_no) - + elif self.doc.purpose in ["Material Receipt", "Manufacture/Repack"]: if self.doc.purpose=="Material Receipt": self.doc.from_warehouse = "" @@ -471,6 +480,7 @@ class DocType(StockController): }, bom_no=self.doc.bom_no) self.get_stock_and_rate() + def get_bom_raw_materials(self, qty): """ diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py index 58cf11bfdf..476a6f6478 100644 --- a/stock/doctype/warehouse/warehouse.py +++ b/stock/doctype/warehouse/warehouse.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cint, flt, validate_email_add -from webnotes.model.code import get_obj from webnotes import msgprint, _ sql = webnotes.conn.sql @@ -83,103 +82,15 @@ class DocType: webnotes.conn.delete_doc("Account", old_warehouse_account) + from utilities.repost_stock import repost for item_code in items: - self.repost(item_code[0], self.doc.merge_with) + repost(item_code[0], self.doc.merge_with) webnotes.conn.auto_commit_on_many_writes = 0 msgprint("Warehouse %s merged into %s. Now you can delete warehouse: %s" % (self.doc.name, self.doc.merge_with, self.doc.name)) - - def repost(self, item_code, warehouse=None): - from stock.utils import get_bin - self.repost_actual_qty(item_code, warehouse) - - bin = get_bin(item_code, warehouse) - self.repost_reserved_qty(bin) - self.repost_indented_qty(bin) - self.repost_ordered_qty(bin) - self.repost_planned_qty(bin) - bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.planned_qty) \ - + flt(bin.doc.indented_qty) + flt(bin.doc.ordered_qty) - flt(bin.doc.reserved_qty) - bin.doc.save() - - - def repost_actual_qty(self, item_code, warehouse=None): - from stock.stock_ledger import update_entries_after - if not warehouse: - warehouse = self.doc.name - - update_entries_after({ "item_code": item_code, "warehouse": warehouse }) - - def repost_reserved_qty(self, bin): - reserved_qty = webnotes.conn.sql(""" - select - sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) - from - ( - select - qty as dnpi_qty, - ( - select qty from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_qty, - ( - select ifnull(delivered_qty, 0) from `tabSales Order Item` - where name = dnpi.parent_detail_docname - ) as so_item_delivered_qty - from - ( - select qty, parent_detail_docname - from `tabDelivery Note Packing Item` dnpi_in - where item_code = %s and warehouse = %s - and parenttype="Sales Order" - and exists (select * from `tabSales Order` so - where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') - ) dnpi - ) tab - where - so_item_qty >= so_item_delivered_qty - """, (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.reserved_qty) != flt(reserved_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "reserved_qty", flt(reserved_qty[0][0])) - - - def repost_indented_qty(self, bin): - indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) - from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr - where pr_item.item_code=%s and pr_item.warehouse=%s - and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name - and pr.status!='Stopped' and pr.docstatus=1""" - , (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.indented_qty) != flt(indented_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "indented_qty", flt(indented_qty[0][0])) - - - def repost_ordered_qty(self, bin): - ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""" - , (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.ordered_qty) != flt(ordered_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "ordered_qty", flt(ordered_qty[0][0])) - - def repost_planned_qty(self, bin): - planned_qty = webnotes.conn.sql(""" - select sum(qty - produced_qty) from `tabProduction Order` - where production_item = %s and fg_warehouse = %s and status != "Stopped" - and docstatus=1""", (bin.doc.item_code, bin.doc.warehouse)) - - if flt(bin.doc.planned_qty) != flt(planned_qty[0][0]): - webnotes.conn.set_value("Bin", bin.doc.name, "planned_qty", flt(planned_qty[0][0])) - def on_trash(self): # delete bin bins = sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1) diff --git a/stock/utils.py b/stock/utils.py index 983ee72c05..0f801c74bc 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -393,13 +393,4 @@ def notify_errors(exceptions_list): Administrator""" % ("\n\n".join(["\n".join(msg) for msg in exceptions_list]),) from webnotes.profile import get_system_managers - sendmail(get_system_managers(), subject=subject, msg=msg) - - -def repost(): - """ - Repost everything! - """ - from webnotes.model.code import get_obj - for wh in webnotes.conn.sql("select name from tabWarehouse"): - get_obj('Warehouse', wh[0]).repost_stock() + sendmail(get_system_managers(), subject=subject, msg=msg) \ No newline at end of file diff --git a/utilities/repost_stock.py b/utilities/repost_stock.py new file mode 100644 index 0000000000..b46aae608f --- /dev/null +++ b/utilities/repost_stock.py @@ -0,0 +1,119 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +from webnotes.utils import flt + + +def repost(): + """ + Repost everything! + """ + webnotes.conn.auto_commit_on_many_writes = 1 + + for d in webnotes.conn.sql("select item_code, warehouse from tabBin"): + repost_stock(d[0], d[1]) + + webnotes.conn.auto_commit_on_many_writes = 0 + +def repost_stock(item_code, warehouse): + repost_actual_qty(item_code, warehouse) + + if item_code and warehouse: + update_bin(item_code, warehouse, { + "reserved_qty": get_reserved_qty(item_code, warehouse), + "indented_qty": get_indented_qty(item_code, warehouse), + "ordered_qty": get_ordered_qty(item_code, warehouse), + "planned_qty": get_planned_qty(item_code, warehouse) + }) + +def repost_actual_qty(item_code, warehouse): + from stock.stock_ledger import update_entries_after + update_entries_after({ "item_code": item_code, "warehouse": warehouse }) + +def get_reserved_qty(item_code, warehouse): + reserved_qty = webnotes.conn.sql(""" + select + sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) + from + ( + (select + qty as dnpi_qty, + ( + select qty from `tabSales Order Item` + where name = dnpi.parent_detail_docname + ) as so_item_qty, + ( + select ifnull(delivered_qty, 0) from `tabSales Order Item` + where name = dnpi.parent_detail_docname + ) as so_item_delivered_qty, + parent, name + from + ( + select qty, parent_detail_docname, parent, name + from `tabDelivery Note Packing Item` dnpi_in + where item_code = %s and warehouse = %s + and parenttype="Sales Order" + and item_code != parent_item + and exists (select * from `tabSales Order` so + where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped') + ) dnpi) + union + (select qty as dnpi_qty, qty as so_item_qty, + ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name + from `tabSales Order Item` so_item + where item_code = %s and reserved_warehouse = %s + and exists(select * from `tabSales Order` so + where so.name = so_item.parent and so.docstatus = 1 + and so.status != 'Stopped')) + ) tab + where + so_item_qty >= so_item_delivered_qty + """, (item_code, warehouse, item_code, warehouse)) + + return flt(reserved_qty[0][0]) if reserved_qty else 0 + +def get_indented_qty(item_code, warehouse): + indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) + from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr + where pr_item.item_code=%s and pr_item.warehouse=%s + and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name + and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse)) + + return flt(indented_qty[0][0]) if indented_qty else 0 + +def get_ordered_qty(item_code, warehouse): + ordered_qty = webnotes.conn.sql(""" + select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + from `tabPurchase Order Item` po_item, `tabPurchase Order` po + where po_item.item_code=%s and po_item.warehouse=%s + and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) + + return flt(ordered_qty[0][0]) if ordered_qty else 0 + +def get_planned_qty(item_code, warehouse): + planned_qty = webnotes.conn.sql(""" + select sum(qty - produced_qty) from `tabProduction Order` + where production_item = %s and fg_warehouse = %s and status != "Stopped" + and docstatus=1 and qty > produced_qty""", (item_code, warehouse)) + + return flt(planned_qty[0][0]) if planned_qty else 0 + + +def update_bin(item_code, warehouse, qty_dict=None): + from stock.utils import get_bin + bin = get_bin(item_code, warehouse) + mismatch = False + for fld, val in qty_dict.items(): + if flt(bin.doc.fields.get(fld)) != flt(val): + bin.doc.fields[fld] = flt(val) + mismatch = True + + if mismatch: + bin.doc.projected_qty = flt(bin.doc.actual_qty) + flt(bin.doc.ordered_qty) + \ + flt(bin.doc.indented_qty) + flt(bin.doc.planned_qty) - flt(bin.doc.reserved_qty) + + bin.doc.save() \ No newline at end of file From 7837827e30190b5090de47d91a0f01974c638e4c Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Fri, 11 Oct 2013 19:06:30 +0530 Subject: [PATCH 109/123] [fix] [minor] conversion arte related fixes --- .../doctype/sales_invoice/sales_invoice.js | 1 - controllers/accounts_controller.py | 11 +++-- controllers/selling_controller.py | 6 +-- public/js/transaction.js | 43 ++++++++++--------- utilities/transaction_base.py | 1 - 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index 5220c0fa20..46e336f029 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -147,7 +147,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }); } } - }, debit_to: function() { diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 927b24980f..3af9c7a547 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -52,7 +52,7 @@ class AccountsController(TransactionBase): msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") + self.doc.doctype + _(" can not be made."), raise_exception=1) - def set_price_list_currency(self, buying_or_selling): + def set_price_list_currency(self, buying_or_selling, for_validate=False): if self.meta.get_field("currency"): company_currency = get_company_currency(self.doc.company) @@ -60,14 +60,13 @@ class AccountsController(TransactionBase): fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \ else "buying_price_list" if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname): - if not self.doc.price_list_currency: - self.doc.price_list_currency = webnotes.conn.get_value("Price List", - self.doc.fields.get(fieldname), "currency") + self.doc.price_list_currency = webnotes.conn.get_value("Price List", + self.doc.fields.get(fieldname), "currency") if self.doc.price_list_currency == company_currency: self.doc.plc_conversion_rate = 1.0 - elif not self.doc.plc_conversion_rate: + elif not self.doc.plc_conversion_rate or not for_validate: self.doc.plc_conversion_rate = self.get_exchange_rate( self.doc.price_list_currency, company_currency) @@ -77,7 +76,7 @@ class AccountsController(TransactionBase): self.doc.conversion_rate = self.doc.plc_conversion_rate elif self.doc.currency == company_currency: self.doc.conversion_rate = 1.0 - elif not self.doc.conversion_rate: + elif not self.doc.conversion_rate or not for_validate: self.doc.conversion_rate = self.get_exchange_rate(self.doc.currency, company_currency) diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 37674ee4bf..845ba859e0 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -20,7 +20,7 @@ class SellingController(StockController): # set contact and address details for customer, if they are not mentioned self.set_missing_lead_customer_details() - self.set_price_list_and_item_details() + self.set_price_list_and_item_details(for_validate) if self.doc.fields.get("__islocal"): self.set_taxes("other_charges", "charge") @@ -38,8 +38,8 @@ class SellingController(StockController): if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname): self.doc.fields[fieldname] = val - def set_price_list_and_item_details(self): - self.set_price_list_currency("Selling") + def set_price_list_and_item_details(self, for_validate=False): + self.set_price_list_currency("Selling", for_validate) self.set_missing_item_details(get_item_details) def get_other_charges(self): diff --git a/public/js/transaction.js b/public/js/transaction.js index a7be5bdbf5..79ea53623f 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -39,18 +39,19 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ }, onload_post_render: function() { - if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.customer) { - var me = this; - return this.frm.call({ - doc: this.frm.doc, - method: "onload_post_render", - freeze: true, - callback: function(r) { - // remove this call when using client side mapper - me.set_default_values(); - me.set_dynamic_labels(); - } - }); + if(this.frm.doc.__islocal && this.frm.doc.company && + !this.frm.doc.customer && !this.frm.doc.is_pos) { + var me = this; + return this.frm.call({ + doc: this.frm.doc, + method: "onload_post_render", + freeze: true, + callback: function(r) { + // remove this call when using client side mapper + me.set_default_values(); + me.set_dynamic_labels(); + } + }); } }, @@ -130,14 +131,16 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ company: function() { if(this.frm.doc.company && this.frm.fields_dict.currency) { var company_currency = this.get_company_currency(); - if(!this.frm.doc.currency) { + if (!this.frm.doc.currency) { this.frm.set_value("currency", company_currency); } - if(this.frm.doc.currency == company_currency) + if (this.frm.doc.currency == company_currency) { this.frm.set_value("conversion_rate", 1.0); - if(this.frm.doc.price_list_currency == company_currency) + } + if (this.frm.doc.price_list_currency == company_currency) { this.frm.set_value('plc_conversion_rate', 1.0); + } this.frm.script_manager.trigger("currency"); } @@ -150,15 +153,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ currency: function() { var me = this; this.set_dynamic_labels(); - + var company_currency = this.get_company_currency(); if(this.frm.doc.currency !== company_currency) { this.get_exchange_rate(this.frm.doc.currency, company_currency, function(exchange_rate) { - if(exchange_rate) { - me.frm.set_value("conversion_rate", exchange_rate); - me.conversion_rate(); - } + me.frm.set_value("conversion_rate", exchange_rate); + me.conversion_rate(); }); } else { this.conversion_rate(); @@ -172,7 +173,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) { this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); } - + this.calculate_taxes_and_totals(); }, diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 9921910a8a..0f4d6bcacd 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -144,7 +144,6 @@ class TransactionBase(StatusUpdater): def get_customer_address(self, args): args = load_json(args) - webnotes.errprint(args) ret = { 'customer_address' : args["address"], 'address_display' : get_address_display(args["address"]), From 287ce383bed6a9956f56e0257cf94dd4624a0657 Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 14 Oct 2013 10:24:22 +0530 Subject: [PATCH 110/123] [docs] website content added --- docs/user/website/docs.user.website.blog.md | 9 +++++-- docs/user/website/docs.user.website.setup.md | 25 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/docs/user/website/docs.user.website.blog.md b/docs/user/website/docs.user.website.blog.md index ec035a0344..b71836e016 100644 --- a/docs/user/website/docs.user.website.blog.md +++ b/docs/user/website/docs.user.website.blog.md @@ -15,6 +15,11 @@ To create a new blog, just create a new Blog from: ![Blog](img/blog.png) -You can format the blog using the same Markdown format +You can format a blog using the Markdown format.You can also access your blog by going to the page “blog.html”. + + +#### A sample blog-page. + + +![Blog](img/blog-look.png) -You can access your blog by going to the page “blog.html” diff --git a/docs/user/website/docs.user.website.setup.md b/docs/user/website/docs.user.website.setup.md index 3249637c2d..4d1d7c7c07 100644 --- a/docs/user/website/docs.user.website.setup.md +++ b/docs/user/website/docs.user.website.setup.md @@ -29,11 +29,36 @@ To define the Top Bar Menus, Brand, Footers and Home Page, go to: > Website > Website Settings +#### Step 1: Landing Page Details ![Website Setting](img/website-settings.png)
+#### Step 2: Banner Details + +![Website Setting](img/website-settings-1.png) + +
+ +#### Step 3: Top Bar Labels + +![Website Setting](img/website-settings-2.png) + +> Note: Create seperate web pages which will be linked to the main web-icons like company, contact, products etc. + +
+#### Step 4: Footer Details + +![Website Setting](img/website-settings-3.png) + +A website can be generated once all the settings and style requirements are added. + +A sample website generated by ERPNext would look like this. + +![Website](img/website-settings-4.png) + +
#### Top Menu From 74ec868968811119d5b53de98b611de24612759c Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 13:41:55 +0530 Subject: [PATCH 111/123] [fix] [minor] added for validate in buying controller --- controllers/buying_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 25d76aa66d..1115b49677 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -30,7 +30,7 @@ class BuyingController(StockController): super(BuyingController, self).set_missing_values(for_validate) self.set_supplier_from_item_default() - self.set_price_list_currency("Buying") + self.set_price_list_currency("Buying", for_validate) # set contact and address details for supplier, if they are not mentioned if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address): From b5e74d7fa69a59962297b6401a8677816b8b107a Mon Sep 17 00:00:00 2001 From: Priya Date: Mon, 14 Oct 2013 14:20:03 +0530 Subject: [PATCH 112/123] [docs] minor name details added --- docs/user/docs.user.md | 10 ++-- .../docs.user.five_day_setup.day_1.md | 2 +- .../docs.user.five_day_setup.day_2.md | 2 +- .../docs.user.five_day_setup.day_3.md | 2 +- .../docs.user.five_day_setup.day_4.md | 2 +- .../docs.user.five_day_setup.day_5.md | 2 +- .../intro/docs.user.implement.strategy.md | 1 + docs/user/stock/docs.user.stock.item.md | 56 +++++++++++++++++++ 8 files changed, 67 insertions(+), 10 deletions(-) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 53e5534185..5c6588272e 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -31,11 +31,11 @@ Contents 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) 1. [Five-Day-Setup](docs.user.five_day_setup.html) - 1. [Day-1](docs.user.five_day_setup.day_1.html) - 1. [Day-2](docs.user.five_day_setup.day_2.html) - 1. [Day-3](docs.user.five_day_setup.day_3.html) - 1. [Day-4](docs.user.five_day_setup.day_4.html) - 1. [Day-5](docs.user.five_day_setup.day_5.html) + 1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html) + 1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html) + 1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html) + 1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html) + 1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index a64f833bd7..9f39810f1a 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-1" + "_label": "Day-1: Setup Customer, Item, and Supplier" } --- Login to your ERPNext account with the User ID and Password sent through the mail. diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index 11e13e2ea9..d2e826f5e7 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-2" + "_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR" } --- diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index a916837227..4a15f5c90b 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-3" + "_label": "Day-3: Sales Cycle and Purchase Cycle" } --- After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index c93a63212d..cdd43f0a75 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-4" + "_label": "Day-4: Manufacturing Cycle and Accounting Reports" } --- diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index b69fccd6ed..d0572db3c2 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-5" + "_label": "Day-5: Projects Calendar and Website" } --- diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md index 735fe1e525..e077a90e56 100644 --- a/docs/user/intro/docs.user.implement.strategy.md +++ b/docs/user/intro/docs.user.implement.strategy.md @@ -10,6 +10,7 @@ Before you start managing your Operations in EPRNext, you must first become fami ### Test Phase - Read the Manual +- Follow the Five-Day-Setup Module or the instructions given below. - Create your first Customer, Supplier and Item. Add a few more so you get familiar with them. - Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items. - Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md index 76a83a2afa..f7746c4842 100644 --- a/docs/user/stock/docs.user.stock.item.md +++ b/docs/user/stock/docs.user.stock.item.md @@ -91,3 +91,59 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi Visit [Manufacturing](docs.user.mfg.html) and [Website](docs.user.website.html) to understand these topics in detail. + +### Listing Item on Website + +To list your Item on the Website, fill the Item details and save the file. Once the file is saved, a plus (+) button will appear next to the Image icon. Click on the plus button and add your Item image. The html code will be generated automatically. + +##### Step 1: Save Image + +![Webimage](img/item-webimage.png) + +
+ +##### Step 2: Check the 'Show in Website' box. + +Under the Website section, please check the box that says 'show in Website'. Once the box is checked, the page will display other fields for entering information. + +![Webimage](img/item-webimage-1.png) + +
+ + +##### Step 3: Enter Website Details + +![Webimage](img/item-webimage-2.png) + + +The page name will be generated automatically. Mention the Item-Group under which the Item will be displayed. + +#### Item Groups + +Mention the Item Group under this column. If you wish to list your Item under the broad category products, name your Item Group as Products. In case you have various varieties of Item and want to classify them under different names, make Item Groups with those names and check the box that says 'show in Website'. For Example, if you wish to create a category called 'Bags', create a Item Group named Bags. + + +![Item Group](img/itemgroup-webimage-bags.png) + +Once the Item Group is created go to the Website Settings page under Website. Enter the Label, Url, and Parent Label. + + +![Item Group](img/itemgroup-website-settings.png) + +
+ +#### Webpage labels + +![Webpage](img/webpage-labels.png) + +Add more Items under a particular Item Group. + +To add more Items under a certain Label, mention the Item Group on the Item Page. The Items will be added automatically on the Webpage, under the Item Group Label. For Example, To add Item-Kiddies Bag and Butterfly Print Bag, check the 'Show in Website'box. The Items will be placed under the Label Bags on the Webpage. + +![Item Group](img/itemgroup-websettings.png) + +
+ +Item Group Display + +![Item Group Display](img/webpage-itemgroup-display.png) \ No newline at end of file From 1a60fd8906068013bd4ecaf0769355d5828f2af9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 14 Oct 2013 14:27:08 +0530 Subject: [PATCH 113/123] [fix] [minor] fixes in reposting of ordered, indented and planned qty --- utilities/repost_stock.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utilities/repost_stock.py b/utilities/repost_stock.py index b46aae608f..735930486e 100644 --- a/utilities/repost_stock.py +++ b/utilities/repost_stock.py @@ -76,29 +76,29 @@ def get_reserved_qty(item_code, warehouse): return flt(reserved_qty[0][0]) if reserved_qty else 0 def get_indented_qty(item_code, warehouse): - indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - pr_item.ordered_qty) + indented_qty = webnotes.conn.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0)) from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr where pr_item.item_code=%s and pr_item.warehouse=%s - and pr_item.qty > pr_item.ordered_qty and pr_item.parent=pr.name + and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse)) return flt(indented_qty[0][0]) if indented_qty else 0 def get_ordered_qty(item_code, warehouse): ordered_qty = webnotes.conn.sql(""" - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) + select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor) from `tabPurchase Order Item` po_item, `tabPurchase Order` po where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name + and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) return flt(ordered_qty[0][0]) if ordered_qty else 0 def get_planned_qty(item_code, warehouse): planned_qty = webnotes.conn.sql(""" - select sum(qty - produced_qty) from `tabProduction Order` + select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order` where production_item = %s and fg_warehouse = %s and status != "Stopped" - and docstatus=1 and qty > produced_qty""", (item_code, warehouse)) + and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse)) return flt(planned_qty[0][0]) if planned_qty else 0 From 6bc48070a1c4bcda34ada8f9f262bfd3a2bced0c Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 14 Oct 2013 15:48:57 +0530 Subject: [PATCH 114/123] Moved Custom Server Scripts to custom_scripts/doctype_name.py --- .../p05_server_custom_script_to_file.py | 35 +++++++++++++++++++ patches/patch_list.py | 1 + 2 files changed, 36 insertions(+) create mode 100644 patches/october_2013/p05_server_custom_script_to_file.py diff --git a/patches/october_2013/p05_server_custom_script_to_file.py b/patches/october_2013/p05_server_custom_script_to_file.py new file mode 100644 index 0000000000..93cfa346ef --- /dev/null +++ b/patches/october_2013/p05_server_custom_script_to_file.py @@ -0,0 +1,35 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + """ + Assuming that some kind of indentation exists: + - Find indentation of server custom script + - replace indentation with tabs + - Add line: + class CustomDocType(DocType): + - Add tab indented code after this line + - Write to file + - Delete custom script record + """ + from core.doctype.custom_script.custom_script import make_custom_server_script_file + for name, dt, script in webnotes.conn.sql("""select name, dt, script from `tabCustom Script` + where script_type='Server'"""): + if script.strip(): + script = indent_using_tabs(script) + make_custom_server_script_file(dt, script) + webnotes.delete_doc("Custom Script", name) + +def indent_using_tabs(script): + for line in script.split("\n"): + try: + indentation_used = line[:line.index("def ")] + script = script.replace(indentation_used, "\t") + break + except ValueError: + pass + + return script \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 92dd52742c..8a79155a51 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -225,4 +225,5 @@ patch_list = [ "patches.october_2013.p03_crm_update_status", "execute:webnotes.delete_doc('DocType', 'Setup Control')", "patches.october_2013.p04_wsgi_migration", + "patches.october_2013.p05_server_custom_script_to_file", ] \ No newline at end of file From c06cbd5b7128ba5683918f4e3204a7dde1057188 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 15:55:19 +0530 Subject: [PATCH 115/123] [docs] [cleanup] five day setup docs cleanup --- docs/user/docs.user.md | 10 ++-- .../docs.user.five_day_setup.day_1.md | 8 +--- .../docs.user.five_day_setup.day_2.md | 11 +++-- .../docs.user.five_day_setup.day_3.md | 28 ++++++----- .../docs.user.five_day_setup.day_4.md | 46 ++++++++----------- .../docs.user.five_day_setup.day_5.md | 14 +++--- .../docs.user.five_day_setup.md | 3 +- .../docs.user.knowledge.attachment_csv.md | 2 +- docs/user/setup/docs.user.setup.md | 2 +- 9 files changed, 56 insertions(+), 68 deletions(-) diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md index 53e5534185..5c6588272e 100644 --- a/docs/user/docs.user.md +++ b/docs/user/docs.user.md @@ -31,11 +31,11 @@ Contents 1. [Ways to get started](docs.user.intro.try.html) 1. [Getting Help](docs.user.help.html) 1. [Five-Day-Setup](docs.user.five_day_setup.html) - 1. [Day-1](docs.user.five_day_setup.day_1.html) - 1. [Day-2](docs.user.five_day_setup.day_2.html) - 1. [Day-3](docs.user.five_day_setup.day_3.html) - 1. [Day-4](docs.user.five_day_setup.day_4.html) - 1. [Day-5](docs.user.five_day_setup.day_5.html) + 1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html) + 1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html) + 1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html) + 1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html) + 1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html) 1. [Implementation](docs.user.implement.html) 1. [Implementation Strategy](docs.user.implement.strategy.html) 1. [Concepts](docs.user.implement.concepts.html) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md index a64f833bd7..80215373ba 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-1" + "_label": "Day-1: Setup Customer,Item, and Supplier" } --- Login to your ERPNext account with the User ID and Password sent through the mail. @@ -10,10 +10,8 @@ After logging into your account you will receive a pop-up form to fill. Please f #### Form Part I ![1st Form](img/firstdaysetup-1.png) -
+

#### Form Part II -
- To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html) @@ -61,8 +59,6 @@ To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.h
#### Setup Page - Suppliers -
- On the Setup page go to Supplier. ![Supplier](img/firstdaysetup-supplier.png) diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md index 11e13e2ea9..f01662319b 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md @@ -1,11 +1,11 @@ --- { - "_label": "Day-2" + "_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR" } --- -#### Setup Page- Accounts - +#### Setup Page - Accounts +
Go to the Accounts icon and make ledgers under Chart of Accounts. ![Accounts](img/seconddaysetup-accounts.png) @@ -21,8 +21,6 @@ Create acccounting ledgers. To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. -
- ![Ledger](img/seconddaysetup-accounts-jv.png)
@@ -30,6 +28,8 @@ To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page. To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html). +
+ #### Opening Stock You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item. @@ -40,6 +40,7 @@ You can upload your opening stock in the system using Stock Reconciliation. Stoc To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html). +
#### Setup Page - HR Setup diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md index a916837227..20536cabf9 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-3" + "_label": "Day-3: Sales Cycle and Purchase Cycle" } --- After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process. @@ -8,8 +8,10 @@ After completing the set-up and account opening process, it is advisable to com ### Sales Cycle -Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) +Complete a standard Sales Cycle. +> Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher) +
#### Lead To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead. @@ -20,6 +22,7 @@ Fill the Lead form. > To understand Lead in detail, visit [Lead](docs.user.selling.lead.html) +
#### Opportunity After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page. @@ -38,7 +41,7 @@ You can also generate an Opportunity directly from the Selling Page. > To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html). - +
#### Quotation Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation. @@ -49,7 +52,7 @@ You can also generate a Quotation directly from the Selling Page. > To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html) - +
#### Sales Order Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order. @@ -60,6 +63,7 @@ You can also generate a Sales Order directly from the Selling Page. > To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html). +
#### Delivery Note If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery. @@ -69,7 +73,7 @@ If your organisation has the practice of sending Delivery Note, this section wil > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) - +
#### Sales Invoice Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order. @@ -91,9 +95,10 @@ A Journal Voucher or a payment entry can be generated directly from the Sales In ### Purchase Cycle -Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). - +Complete a standard Purchase Cycle. +> Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher). +
#### Material Request To create a Material Request, go to Stock/Buying and Click on Material Request. @@ -102,6 +107,7 @@ To create a Material Request, go to Stock/Buying and Click on Material Request. > To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html) +
#### Purchase Order To create a Purchase Order go to Buying and click on Purchase Order @@ -110,26 +116,24 @@ To create a Purchase Order go to Buying and click on Purchase Order > To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html) +
#### Purchase Receipt To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt. ![Purchase Receipt](img/thirddaysetup-purchase-receipt.png) -
>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html)
-#### Payment( Journal Voucher) +#### Payment (Journal Voucher) Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices. ![Payment Entry](img/thirddaysetup-payment-entry.png) -
-> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). - +> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html). \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md index c93a63212d..eb2b58b1ea 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md @@ -1,86 +1,76 @@ --- { - "_label": "Day-4" + "_label": "Day-4: Manufacturing Cycle and Accounting Reports" } --- ### Manufacturing Cycle -Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (material issue) > Stock Entry (sales return) +Complete a manufacturing cycle (if applicable). +> BOM > Production Planning Tool > Production Order > Stock Entry (Material Issue) > Stock Entry (Sales Return) +
#### Bill of Materials To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials. ![Bill of Materials](img/fourthdaysetup-bom.png) -
- > To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html) +
#### Production Planning Tool To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page. ![Production Planning Page](img/fourthdaysetup-ppt.png) -
- > To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html) - +
#### Production Order To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order. ![Production Order](img/fourthdaysetup-po.png) -
- > To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html) +
#### Stock Entry To go to Stock Entry, click on the Stock Icon and go to Stock Entry. ![Stock Entry](img/fourthdaysetup-stock.png) +> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html). + +> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html). +
- -> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html) - - -> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html) - - #### Delivery Note To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note. ![Delivery Note](img/fourthdaysetup-delivery-note.png) -
- > To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html) - - +
#### Warehouse To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse. ![Warehouse](img/fourthdaysetup-warehouse.png) +> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) +
- -> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html) - - #### Accounts Make a few Journal Vouchers. Generate some Accounting Reports. -#### Journal Voucher. +#### Journal Voucher To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher. @@ -88,9 +78,9 @@ To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Jo > To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html) -#### Accounting Reports +
+### Accounting Reports Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register. -> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) - +> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html) \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md index b69fccd6ed..e8a6f087b1 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md @@ -1,6 +1,6 @@ --- { - "_label": "Day-5" + "_label": "Day-5: Projects, Calendar, and Website" } --- @@ -8,6 +8,7 @@ ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people. +
#### Tasks Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project. @@ -16,19 +17,16 @@ To create a Task, go to Project and click on Task. ![Tasks](img/fifthdaysetup-tasks.png) -
- - -> To understand Projects in detail, visit [Projects](docs.user.projects.html) +> To understand Projects in detail, visit [Projects](docs.user.projects.html). > To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html) +
#### Calendar > To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html) - +
#### Website -> To understand Website in detail, visit [Website](docs.user.website.html) - +> To understand Website in detail, visit [Website](docs.user.website.html) \ No newline at end of file diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.md b/docs/user/five_day_setup/docs.user.five_day_setup.md index d296914f9e..90aeb56c22 100644 --- a/docs/user/five_day_setup/docs.user.five_day_setup.md +++ b/docs/user/five_day_setup/docs.user.five_day_setup.md @@ -45,5 +45,4 @@ The setup help is divided into day-wise instructions for 5 consecutive days. - Projects - Calendar -- Website - +- Website \ No newline at end of file diff --git a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md index 311934d7f4..eecc42ddcf 100644 --- a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md +++ b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md @@ -1,6 +1,6 @@ --- { - "_label": "Attachement and CSV files" + "_label": "Attachment and CSV files" } --- diff --git a/docs/user/setup/docs.user.setup.md b/docs/user/setup/docs.user.setup.md index fa9680a062..585811f66e 100644 --- a/docs/user/setup/docs.user.setup.md +++ b/docs/user/setup/docs.user.setup.md @@ -18,7 +18,7 @@ "docs.user.setup.email", "docs.user.setup.sms", "docs.user.setup.taxes", - "docs.user.setup.price_lists", + "docs.user.setup.price_list", "docs.user.setup.opening", "docs.user.setup.pos_setting", "docs.user.setup.third_party_backups" From 570b1070a8bf4478f8c60cd77c2810572658d626 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 14 Oct 2013 17:54:28 +0530 Subject: [PATCH 116/123] [fix] [minor] stock balance report for serialized item --- public/js/stock_grid_report.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js index 46370d27f6..495ea43e40 100644 --- a/public/js/stock_grid_report.js +++ b/public/js/stock_grid_report.js @@ -28,9 +28,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ var value_diff = (rate * add_qty); if(add_qty) - wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); - - if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl); + wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]); } else { // outgoing if(sl.serial_no) { @@ -113,7 +111,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({ $.each(wn.report_dump.data["Stock Ledger Entry"], function(i, sle) { if(sle.qty > 0 && sle.serial_no) { $.each(sle.serial_no.trim().split("\n"), function(i, sr) { - if(sr && sle.incoming_rate !== undefined) { + if(sr && sle.incoming_rate !== undefined + && !serialized_buying_rates[sr.trim().toLowerCase()]) { serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate); } }); From 1e58ecdc74218826800425d01ac68ab58384b91b Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Mon, 14 Oct 2013 18:22:26 +0530 Subject: [PATCH 117/123] [docs] updated pos and price list docs --- docs/user/accounts/docs.user.accounts.pos.md | 19 ++++++++++--------- docs/user/setup/docs.user.setup.price_list.md | 13 ++++++++++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/docs/user/accounts/docs.user.accounts.pos.md b/docs/user/accounts/docs.user.accounts.pos.md index 654a5d6dfa..7bd668ef72 100644 --- a/docs/user/accounts/docs.user.accounts.pos.md +++ b/docs/user/accounts/docs.user.accounts.pos.md @@ -13,33 +13,34 @@ You can make a Sales Invoice of type POS by checking on “Is POS”. When you c - Update Stock: If this is checked, Stock Ledger Entries will be made when you “Submit” this Sales Invoice thereby eliminating the need for a separate Delivery Note.
 - In your Items table, update inventory information like Warehouse (saved as default), Serial Number, or Batch Number if applicable.
 -- Update Payment Details like your Bank / Cash Account, paid amount etc.
 +- Update Payment Details like your Bank / Cash Account, Paid amount etc.
 - If you are writing off certain amount. For example when you receive extra cash as a result of not having exact denomination of change, check on ‘Write off Outstanding Amount’ and set the Account. -Setup [POS Setting](docs.user.setup.pos_setting.html) #### Enable POS View -Sales Invoice has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred. +- Every Sales & Purchase documents has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred. > Setup > Show/Hide Features ![POS View](img/pos-features-setup.png) +- Setup [POS Setting](docs.user.setup.pos_setting.html) + ### Adding an Item -At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode. +At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode / Serial No. **Select Item** - To select a product click on the Item image and add it into the cart. A cart is an area that prepares a customer for checkout by allowing to edit product information, adjust taxes and add discounts. -**Barcode** - A Barcode is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode in the barcode box and pause for a second. The Item will be automatically added to the cart. +**Barcode / Serial No** - A Barcode / Serial No is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode / Serial No in the box as shown in the image below and pause for a second, the item will be automatically added to the cart. ![POS](img/pos-add-item.png) > Tip: To change the quantity of an Item, enter your desired quantity in the quantity box. These are mostly used if the same Item is purchased in bulk. -If your product list is very long use the universal search field, to type the product name and select faster. +If your product list is very long use the Search field, type the product name in Search box. ### Removing an Item @@ -48,7 +49,7 @@ There are two ways to remove an Item. - Select an Item by clicking on the row of that Item from Item cart. Then click on “Del” button. OR -- Type 0 in the ‘select quantity’ field to delete the record. +- Enter 0(zero) quantity of any item to delete that item. To remove multiple Items together, select multiple rows & click on “Del” button. @@ -62,11 +63,11 @@ After all the Items and their quantities are added into the cart, you are ready 1. Click on “Make Payment” to get the Payment window. 1. Select your “Mode of Payment”. -1. Click on “Pay” button to Save the Sales Invoice. +1. Click on “Pay” button to Save the document. ![POS Payment](img/pos-make-payment.png) -Submit the document to finalise the record. After the Invoice is submitted, you can either print an invoice or email it directly to the customer. +Submit the document to finalise the record. After the document is submitted, you can either print or email it directly to the customer. #### Accounting entries (GL Entry) for a Point of Sale: diff --git a/docs/user/setup/docs.user.setup.price_list.md b/docs/user/setup/docs.user.setup.price_list.md index 021df09041..7214fff514 100644 --- a/docs/user/setup/docs.user.setup.price_list.md +++ b/docs/user/setup/docs.user.setup.price_list.md @@ -7,7 +7,7 @@ A Price List is a place where different rate plans can be stored. It’s a name An Item can have multiple prices based on customer, currency, region, shipping cost etc, which can be stored as different rate plans. In ERPNext, you are required to store all the lists seperately. Buying Price List is different from Selling Price List and thus is stored separately. -> Selling > Price List +> Setup > Price List ![Price-List](img/price-lists.png) @@ -15,7 +15,14 @@ An Item can have multiple prices based on customer, currency, region, shipping c > For multiple currencies, maintain multiple Price Lists. +
+### Add Item in Price List -To add a new Item to the Price List, add the Item Code and its rate in the Item Prices table. +> Setup > Item Price -You can also import Item Prices via [Data Import Tool](docs.user.setup.data_import.html) \ No newline at end of file +- Enter Price List and Item Code, Valid for Buying or Selling, Item Name & Item Description will be automatically fetched. +- Enter Rate and save the document. + +![Item-Price](img/item-price.png) + +For bulk upload of Item Prices, use [Data Import Tool](docs.user.setup.data_import.html) \ No newline at end of file From 3510764e7c8fd03aab0b16678b846b547237c21d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 14 Oct 2013 18:59:16 +0530 Subject: [PATCH 118/123] [minor] plugin architecture, first cut --- .../p05_server_custom_script_to_file.py | 3 ++- utilities/demo/demo_control_panel.py | 27 ++++++++++--------- utilities/demo/demo_docs/Lead.csv | 12 ++++----- utilities/demo/make_demo.py | 2 +- utilities/demo/make_erpnext_demo.py | 13 +++++---- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/patches/october_2013/p05_server_custom_script_to_file.py b/patches/october_2013/p05_server_custom_script_to_file.py index 93cfa346ef..3a7e770265 100644 --- a/patches/october_2013/p05_server_custom_script_to_file.py +++ b/patches/october_2013/p05_server_custom_script_to_file.py @@ -15,13 +15,14 @@ def execute(): - Write to file - Delete custom script record """ + import os + from webnotes.utils import get_site_base_path from core.doctype.custom_script.custom_script import make_custom_server_script_file for name, dt, script in webnotes.conn.sql("""select name, dt, script from `tabCustom Script` where script_type='Server'"""): if script.strip(): script = indent_using_tabs(script) make_custom_server_script_file(dt, script) - webnotes.delete_doc("Custom Script", name) def indent_using_tabs(script): for line in script.split("\n"): diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py index 3123f41e08..694f7d1201 100644 --- a/utilities/demo/demo_control_panel.py +++ b/utilities/demo/demo_control_panel.py @@ -1,13 +1,16 @@ +from __future__ import unicode_literals +import webnotes - def on_login(self): - from webnotes.utils import validate_email_add - from webnotes import conf - if "demo_notify_url" in conf: - if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email): - import requests - response = requests.post(conf.demo_notify_url, data={ - "cmd":"portal.utils.send_message", - "subject":"Logged into Demo", - "sender": webnotes.form_dict.lead_email, - "message": "via demo.erpnext.com" - }) +class CustomDocType(DocType): + def on_login(self): + from webnotes.utils import validate_email_add + from webnotes import conf + if "demo_notify_url" in conf: + if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email): + import requests + response = requests.post(conf.demo_notify_url, data={ + "cmd":"portal.utils.send_message", + "subject":"Logged into Demo", + "sender": webnotes.form_dict.lead_email, + "message": "via demo.erpnext.com" + }) diff --git a/utilities/demo/demo_docs/Lead.csv b/utilities/demo/demo_docs/Lead.csv index a97fe3bacb..a7004e4810 100644 --- a/utilities/demo/demo_docs/Lead.csv +++ b/utilities/demo/demo_docs/Lead.csv @@ -1,5 +1,5 @@ Data Import Template,,,,,,,,,,,,,,,,,,,,,,,,,, -Table:,Lead,,,,,,,,,,,,,,,,,,,,,,,,,, +Table:,Lead,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,, Notes:,,,,,,,,,,,,,,,,,,,,,,,,,, @@ -11,11 +11,11 @@ Only mandatory fields are necessary for new records. You can delete non-mandator "If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,,,,,, You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,, -Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Next Contact By,Next Contact Date,Last Contact Date,Company,Unsubscribed,Blog Subscriber -Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,contact_by,contact_date,last_contact_date,company,unsubscribed,blog_subscriber -Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No -Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Date,Date,Link,Check,Check -Info:,,,"Lead, Open, Replied, Opportunity, Interested, Converted, Do Not Contact","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Profile,,,Valid Company,0 or 1,0 or 1 +Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Next Contact By,Next Contact Date,Company,Unsubscribed,Blog Subscriber, +Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,contact_by,contact_date,company,unsubscribed,blog_subscriber, +Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No, +Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Date,Link,Check,Check, +Info:,,,"Lead, Open, Replied, Opportunity, Interested, Converted, Do Not Contact","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Profile,,Valid Company,0 or 1,0 or 1, Start entering data below this line,,,,,,,,,,,,,,,,,,,,,,,,,, ,,Mart Lakeman,Lead,,Zany Brainy,MartLakeman@einrot.com,,,,,,,,,,,,,,,,,,,, ,,Saga Lundqvist,Lead,,Patterson-Fletcher,SagaLundqvist@dayrep.com,,,,,,,,,,,,,,,,,,,, diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 219ce86496..9df34c26ae 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -164,7 +164,7 @@ def run_stock(current_date): if can_make("Delivery Note"): from selling.doctype.sales_order.sales_order import make_delivery_note from stock.stock_ledger import NegativeStockError - from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoRequiredError, SerialNoQtyError + from stock.doctype.serial_no.serial_no import SerialNoRequiredError, SerialNoQtyError report = "Ordered Items To Be Delivered" for so in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Delivery Note")]: dn = webnotes.bean(make_delivery_note(so)) diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py index 262a7595c2..cda38d690d 100644 --- a/utilities/demo/make_erpnext_demo.py +++ b/utilities/demo/make_erpnext_demo.py @@ -105,13 +105,12 @@ def make_demo_login_page(): webnotes.conn.commit() def make_demo_on_login_script(): - webnotes.conn.sql("""delete from `tabCustom Script` where dt='Control Panel'""") - s = webnotes.new_bean("Custom Script") - s.doc.dt = "Control Panel" - s.doc.script_type = "Server" - with open(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), "r") as dfile: - s.doc.script = dfile.read() - s.insert() + import shutil + from core.doctype.custom_script.custom_script import get_custom_server_script_path + custom_script_path = get_custom_server_script_path("Control Panel") + webnotes.create_folder(os.path.dirname(custom_script_path)) + + shutil.copyfile(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), custom_script_path) cp = webnotes.bean("Control Panel") cp.doc.custom_startup_code = """wn.ui.toolbar.show_banner('You are using ERPNext Demo. To start your own ERPNext Trial, click here')""" From bfeae2da707699cb3e881b017545caf1e4f5f061 Mon Sep 17 00:00:00 2001 From: Akhilesh Darjee Date: Tue, 15 Oct 2013 11:16:38 +0530 Subject: [PATCH 119/123] [cleanup] [minor] removed conversion rate from pos setting --- accounts/doctype/pos_setting/pos_setting.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/accounts/doctype/pos_setting/pos_setting.txt b/accounts/doctype/pos_setting/pos_setting.txt index 2420ad5503..7eda7fd62f 100755 --- a/accounts/doctype/pos_setting/pos_setting.txt +++ b/accounts/doctype/pos_setting/pos_setting.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 12:15:51", "docstatus": 0, - "modified": "2013-08-28 19:13:42", + "modified": "2013-10-15 11:12:02", "modified_by": "Administrator", "owner": "Administrator" }, @@ -80,16 +80,6 @@ "read_only": 0, "reqd": 1 }, - { - "doctype": "DocField", - "fieldname": "conversion_rate", - "fieldtype": "Float", - "label": "Conversion Rate", - "oldfieldname": "conversion_rate", - "oldfieldtype": "Currency", - "read_only": 0, - "reqd": 1 - }, { "doctype": "DocField", "fieldname": "selling_price_list", From f8924bcf6febd806b4daf214057e371265b67e2c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 15 Oct 2013 12:19:25 +0530 Subject: [PATCH 120/123] [fix] [minor] update serial no in sle while creating auto serial no --- .../sales_invoice/test_sales_invoice.py | 10 +++--- .../purchase_order/test_purchase_order.py | 4 +-- controllers/buying_controller.py | 2 -- .../delivery_note/test_delivery_note.py | 6 ++-- .../material_request/test_material_request.py | 4 +-- .../purchase_receipt/purchase_receipt.py | 4 +-- stock/doctype/serial_no/serial_no.py | 36 +++++++++++-------- stock/doctype/stock_entry/stock_entry.py | 2 +- stock/doctype/stock_entry/test_stock_entry.py | 7 ++-- .../stock_ledger_entry/stock_ledger_entry.py | 5 +-- 10 files changed, 42 insertions(+), 38 deletions(-) diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index dee098a3e4..fbb344ec94 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -641,8 +641,8 @@ class TestSalesInvoice(unittest.TestCase): return new_si - # if yearly, test 3 repetitions, else test 13 repetitions - count = 3 if no_of_months == 12 else 13 + # if yearly, test 3 repetitions, else test 5 repetitions + count = 1 if (no_of_months == 12) else 5 for i in xrange(count): base_si = _test(i) @@ -653,7 +653,7 @@ class TestSalesInvoice(unittest.TestCase): def test_serialized(self): from stock.doctype.stock_entry.test_stock_entry import make_serialized_item - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos se = make_serialized_item() serial_nos = get_serial_nos(se.doclist[1].serial_no) @@ -674,7 +674,7 @@ class TestSalesInvoice(unittest.TestCase): return si def test_serialized_cancel(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos si = self.test_serialized() si.cancel() @@ -686,7 +686,7 @@ class TestSalesInvoice(unittest.TestCase): "delivery_document_no")) def test_serialize_status(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos + from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos from stock.doctype.stock_entry.test_stock_entry import make_serialized_item se = make_serialized_item() diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py index cef5e4a207..bd5f410f6e 100644 --- a/buying/doctype/purchase_order/test_purchase_order.py +++ b/buying/doctype/purchase_order/test_purchase_order.py @@ -98,11 +98,11 @@ class TestPurchaseOrder(unittest.TestCase): self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2) def test_warehouse_company_validation(self): - from controllers.buying_controller import WrongWarehouseCompany + from stock.utils import InvalidWarehouseCompany po = webnotes.bean(copy=test_records[0]) po.doc.company = "_Test Company 1" po.doc.conversion_rate = 0.0167 - self.assertRaises(WrongWarehouseCompany, po.insert) + self.assertRaises(InvalidWarehouseCompany, po.insert) def test_uom_integer_validation(self): from utilities.transaction_base import UOMMustBeIntegerError diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 25d76aa66d..fd3428e6ad 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -11,8 +11,6 @@ from setup.utils import get_company_currency from controllers.stock_controller import StockController -class WrongWarehouseCompany(Exception): pass - class BuyingController(StockController): def onload_post_render(self): # contact, address, item details diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py index 7c525504ae..ca95a50602 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -160,7 +160,7 @@ class TestDeliveryNote(unittest.TestCase): def test_serialized(self): from stock.doctype.stock_entry.test_stock_entry import make_serialized_item - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos se = make_serialized_item() serial_nos = get_serial_nos(se.doclist[1].serial_no) @@ -180,7 +180,7 @@ class TestDeliveryNote(unittest.TestCase): return dn def test_serialized_cancel(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos + from stock.doctype.serial_no.serial_no import get_serial_nos dn = self.test_serialized() dn.cancel() @@ -192,7 +192,7 @@ class TestDeliveryNote(unittest.TestCase): "delivery_document_no")) def test_serialize_status(self): - from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos + from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos from stock.doctype.stock_entry.test_stock_entry import make_serialized_item se = make_serialized_item() diff --git a/stock/doctype/material_request/test_material_request.py b/stock/doctype/material_request/test_material_request.py index 8ebad15810..13fdd02c3c 100644 --- a/stock/doctype/material_request/test_material_request.py +++ b/stock/doctype/material_request/test_material_request.py @@ -315,10 +315,10 @@ class TestMaterialRequest(unittest.TestCase): self.assertRaises(webnotes.MappingMismatchError, se.insert) def test_warehouse_company_validation(self): - from controllers.buying_controller import WrongWarehouseCompany + from stock.utils import InvalidWarehouseCompany mr = webnotes.bean(copy=test_records[0]) mr.doc.company = "_Test Company 1" - self.assertRaises(WrongWarehouseCompany, mr.insert) + self.assertRaises(InvalidWarehouseCompany, mr.insert) test_dependencies = ["Currency Exchange"] test_records = [ diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index 6169b1d916..6d4320fe18 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -7,7 +7,7 @@ import webnotes from webnotes.utils import cstr, flt, cint from webnotes.model.bean import getlist from webnotes.model.code import get_obj -from webnotes import msgprint +from webnotes import msgprint, _ import webnotes.defaults from stock.utils import update_bin @@ -247,7 +247,7 @@ class DocType(BuyingController): self.update_stock() from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit - update_serial_nos_after_submit(self, "Purchase Receipt", "purchase_receipt_details") + update_serial_nos_after_submit(self, "purchase_receipt_details") purchase_controller.update_last_purchase_rate(self, 1) diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py index d806287ecb..f665abc46f 100644 --- a/stock/doctype/serial_no/serial_no.py +++ b/stock/doctype/serial_no/serial_no.py @@ -37,10 +37,7 @@ class DocType(StockController): self.validate_warehouse() self.validate_item() - if self.via_stock_ledger: - self.set_status() - self.set_purchase_details() - self.set_sales_details() + self.on_stock_ledger_entry() def validate_amc_status(self): """ @@ -181,6 +178,12 @@ class DocType(StockController): webnotes.conn.sql("""update `tab%s` set serial_no = %s where name=%s""" % (dt[0], '%s', '%s'), ('\n'.join(serial_nos), item[0])) + + def on_stock_ledger_entry(self): + if self.via_stock_ledger and not self.doc.fields.get("__islocal"): + self.set_status() + self.set_purchase_details() + self.set_sales_details() def process_serial_no(sle): item_det = get_item_details(sle.item_code) @@ -233,6 +236,14 @@ def validate_serial_no(sle, item_det): + sle.item_code), SerialNoRequiredError) def update_serial_nos(sle, item_det): + if not sle.serial_no and sle.actual_qty > 0 and item_det.serial_no_series: + from webnotes.model.doc import make_autoname + serial_nos = [] + for i in xrange(cint(sle.actual_qty)): + serial_nos.append(make_autoname(item_det.serial_no_series)) + + webnotes.conn.set(sle, "serial_no", "\n".join(serial_nos)) + if sle.serial_no: serial_nos = get_serial_nos(sle.serial_no) for serial_no in serial_nos: @@ -243,12 +254,6 @@ def update_serial_nos(sle, item_det): sr.save() elif sle.actual_qty > 0: make_serial_no(serial_no, sle) - elif sle.actual_qty > 0 and item_det.serial_no_series: - from webnotes.model.doc import make_autoname - serial_nos = [] - for i in xrange(cint(sle.actual_qty)): - serial_nos.append(make_serial_no(make_autoname(item_det.serial_no_series), sle)) - sle.serial_no = "\n".join(serial_nos) def get_item_details(item_code): return webnotes.conn.sql("""select name, has_batch_no, docstatus, @@ -270,13 +275,16 @@ def make_serial_no(serial_no, sle): webnotes.msgprint(_("Serial No created") + ": " + sr.doc.name) return sr.doc.name -def update_serial_nos_after_submit(controller, parenttype, parentfield): - if not hasattr(webnotes, "new_stock_ledger_entries"): - return +def update_serial_nos_after_submit(controller, parentfield): + stock_ledger_entries = webnotes.conn.sql("""select voucher_detail_no, serial_no + from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s""", + (controller.doc.doctype, controller.doc.name), as_dict=True) + if not stock_ledger_entries: return + for d in controller.doclist.get({"parentfield": parentfield}): serial_no = None - for sle in webnotes.new_stock_ledger_entries: + for sle in stock_ledger_entries: if sle.voucher_detail_no==d.name: serial_no = sle.serial_no break diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 7d8130cc85..c620bd9c8e 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -55,7 +55,7 @@ class DocType(StockController): self.update_stock_ledger() from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit - update_serial_nos_after_submit(self, "Stock Entry", "mtn_details") + update_serial_nos_after_submit(self, "mtn_details") self.update_production_order() self.make_gl_entries() diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index b41a6269ad..2882072852 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -44,9 +44,10 @@ class TestStockEntry(unittest.TestCase): def test_warehouse_company_validation(self): self._clear_stock_account_balance() - webnotes.session.user = "test2@example.com" webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") + + webnotes.session.user = "test2@example.com" from stock.utils import InvalidWarehouseCompany st1 = webnotes.bean(copy=test_records[0]) @@ -65,14 +66,14 @@ class TestStockEntry(unittest.TestCase): webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - + webnotes.session.user = "test@example.com" + st1 = webnotes.bean(copy=test_records[0]) st1.doc.company = "_Test Company 1" st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() self.assertRaises(UserNotAllowedForWarehouse, st1.submit) - webnotes.session.user = "test2@example.com" st1 = webnotes.bean(copy=test_records[0]) st1.doc.company = "_Test Company 1" st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index bfb0f0aa92..1738efcf3f 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -14,10 +14,7 @@ class DocType(DocListController): def validate(self): from stock.utils import validate_warehouse_user, validate_warehouse_company - if not hasattr(webnotes, "new_stock_ledger_entries"): - webnotes.new_stock_ledger_entries = [] - - webnotes.new_stock_ledger_entries.append(self.doc) + self.validate_mandatory() self.validate_item() validate_warehouse_user(self.doc.warehouse) From f0feb73dedd4c6bd124a40eb1a8694d874c37ed0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 15 Oct 2013 12:22:41 +0530 Subject: [PATCH 121/123] [minor] bypass plugin field related operational error --- patches/patch_list.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/patches/patch_list.py b/patches/patch_list.py index 8a79155a51..266a01fef8 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -3,10 +3,8 @@ from __future__ import unicode_literals patch_list = [ - "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-07-15", - "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-07-15", - "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-07-16", - "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-07-16", + "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-10-15", + "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-10-15", "execute:webnotes.reload_doc('core', 'doctype', 'docperm') #2013-07-16", "execute:webnotes.reload_doc('core', 'doctype', 'page') #2013-07-16", "execute:webnotes.reload_doc('core', 'doctype', 'report') #2013-07-16", From 5101098020fe18d31a965e4a249d682bda2224dc Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 15 Oct 2013 13:00:53 +0530 Subject: [PATCH 122/123] [fix] [minor] fixes in testcases --- stock/doctype/stock_entry/test_stock_entry.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 2882072852..3a18c69693 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -43,6 +43,7 @@ class TestStockEntry(unittest.TestCase): webnotes.conn.set_default("company", self.old_default_company) def test_warehouse_company_validation(self): + set_perpetual_inventory(0) self._clear_stock_account_balance() webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") @@ -58,22 +59,23 @@ class TestStockEntry(unittest.TestCase): webnotes.session.user = "Administrator" def test_warehouse_user(self): + set_perpetual_inventory(0) from stock.utils import UserNotAllowedForWarehouse - webnotes.session.user = "test@example.com" webnotes.bean("Profile", "test@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - webnotes.session.user = "test@example.com" + webnotes.session.user = "test@example.com" st1 = webnotes.bean(copy=test_records[0]) st1.doc.company = "_Test Company 1" st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" st1.insert() self.assertRaises(UserNotAllowedForWarehouse, st1.submit) + webnotes.session.user = "test2@example.com" st1 = webnotes.bean(copy=test_records[0]) st1.doc.company = "_Test Company 1" st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1" From a295bf54214ced9cad2490a562b48409a9a83ebe Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 15 Oct 2013 19:52:29 +0530 Subject: [PATCH 123/123] [minor] don't rollback when running all tests, fixed test cases --- .../test_period_closing_voucher.py | 3 ++ .../purchase_invoice/purchase_invoice.py | 2 +- .../test_leave_application.py | 9 ++-- .../leave_block_list/test_leave_block_list.py | 3 ++ manufacturing/doctype/bom/bom.py | 1 + manufacturing/doctype/bom/test_bom.py | 47 +++++++++++++++---- .../time_log_batch/test_time_log_batch.py | 26 ++++++++-- selling/doctype/customer/test_customer.py | 5 ++ selling/doctype/quotation/test_quotation.py | 10 ++-- .../doctype/sales_order/test_sales_order.py | 9 ++-- .../delivery_note/test_delivery_note.py | 28 ++++++----- stock/doctype/item/test_item.py | 46 +++++++++++++++++- support/doctype/newsletter/newsletter.py | 7 ++- support/doctype/newsletter/test_newsletter.py | 9 ++-- utilities/demo/make_demo.py | 2 +- 15 files changed, 160 insertions(+), 47 deletions(-) diff --git a/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py index c21d63f6ec..b9ac8bd740 100644 --- a/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py +++ b/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py @@ -8,6 +8,9 @@ import webnotes class TestPeriodClosingVoucher(unittest.TestCase): def test_closing_entry(self): + # clear GL Entries + webnotes.conn.sql("""delete from `tabGL Entry`""") + from accounts.doctype.journal_voucher.test_journal_voucher import test_records as jv_records jv = webnotes.bean(copy=jv_records[2]) jv.insert() diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index a562c67a38..c65b9acb2b 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -434,7 +434,7 @@ class DocType(BuyingController): def update_raw_material_cost(self): if self.sub_contracted_items: for d in self.doclist.get({"parentfield": "entries"}): - rm_cost = webnotes.conn.sql(""" select raw_material_cost / quantity + rm_cost = webnotes.conn.sql("""select raw_material_cost / quantity from `tabBOM` where item = %s and is_default = 1 and docstatus = 1 and is_active = 1 """, (d.item_code,)) rm_cost = rm_cost and flt(rm_cost[0][0]) or 0 diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py index c89f7c4537..7a900e3bfe 100644 --- a/hr/doctype/leave_application/test_leave_application.py +++ b/hr/doctype/leave_application/test_leave_application.py @@ -7,6 +7,9 @@ import unittest from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError class TestLeaveApplication(unittest.TestCase): + def tearDown(self): + webnotes.session.user = "Administrator" + def _clear_roles(self): webnotes.conn.sql("""delete from `tabUserRole` where parent in ("test@example.com", "test1@example.com", "test2@example.com")""") @@ -15,6 +18,7 @@ class TestLeaveApplication(unittest.TestCase): webnotes.conn.sql("""delete from `tabLeave Application`""") def _add_employee_leave_approver(self, employee, leave_approver): + temp_session_user = webnotes.session.user webnotes.session.user = "Administrator" employee = webnotes.bean("Employee", employee) employee.doclist.append({ @@ -23,6 +27,7 @@ class TestLeaveApplication(unittest.TestCase): "leave_approver": leave_approver }) employee.save() + webnotes.session.user = temp_session_user def get_application(self, doclist): application = webnotes.bean(copy=doclist) @@ -31,7 +36,6 @@ class TestLeaveApplication(unittest.TestCase): return application def test_block_list(self): - webnotes.session.user = "Administrator" self._clear_roles() from webnotes.profile import add_role @@ -54,7 +58,6 @@ class TestLeaveApplication(unittest.TestCase): self.assertTrue(application.insert()) def test_overlap(self): - webnotes.session.user = "Administrator" self._clear_roles() self._clear_applications() @@ -72,7 +75,6 @@ class TestLeaveApplication(unittest.TestCase): self.assertRaises(OverlapError, application.insert) def test_global_block_list(self): - webnotes.session.user = "Administrator" self._clear_roles() from webnotes.profile import add_role @@ -98,7 +100,6 @@ class TestLeaveApplication(unittest.TestCase): "applies_to_all_departments", 0) def test_leave_approval(self): - webnotes.session.user = "Administrator" self._clear_roles() from webnotes.profile import add_role diff --git a/hr/doctype/leave_block_list/test_leave_block_list.py b/hr/doctype/leave_block_list/test_leave_block_list.py index e266cd84d6..34814d9380 100644 --- a/hr/doctype/leave_block_list/test_leave_block_list.py +++ b/hr/doctype/leave_block_list/test_leave_block_list.py @@ -7,6 +7,9 @@ import unittest from hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates class TestLeaveBlockList(unittest.TestCase): + def tearDown(self): + webnotes.session.user = "Administrator" + def test_get_applicable_block_dates(self): webnotes.session.user = "test@example.com" webnotes.conn.set_value("Department", "_Test Department", "leave_block_list", diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 5954475376..97a2f96c6e 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -332,6 +332,7 @@ class DocType: d.amount = flt(d.rate) * flt(d.qty) d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity) total_rm_cost += d.amount + self.doc.raw_material_cost = total_rm_cost def update_exploded_items(self): diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py index da98faf8f4..2f4424eb97 100644 --- a/manufacturing/doctype/bom/test_bom.py +++ b/manufacturing/doctype/bom/test_bom.py @@ -10,7 +10,7 @@ test_records = [ [ { "doctype": "BOM", - "item": "_Test Item Home Desktop 100", + "item": "_Test Item Home Desktop Manufactured", "quantity": 1.0, "is_active": 1, "is_default": 1, @@ -58,7 +58,36 @@ test_records = [ "doctype": "BOM Item", "item_code": "_Test Item Home Desktop 100", "parentfield": "bom_materials", - "bom_no": "BOM/_Test Item Home Desktop 100/001", + "qty": 2.0, + "rate": 1000.0, + "amount": 2000.0, + "stock_uom": "_Test UOM" + } + ], + + [ + { + "doctype": "BOM", + "item": "_Test FG Item 2", + "quantity": 1.0, + "is_active": 1, + "is_default": 1, + "docstatus": 1 + }, + { + "doctype": "BOM Item", + "item_code": "_Test Item", + "parentfield": "bom_materials", + "qty": 1.0, + "rate": 5000.0, + "amount": 5000.0, + "stock_uom": "_Test UOM" + }, + { + "doctype": "BOM Item", + "item_code": "_Test Item Home Desktop Manufactured", + "bom_no": "BOM/_Test Item Home Desktop Manufactured/001", + "parentfield": "bom_materials", "qty": 2.0, "rate": 1000.0, "amount": 2000.0, @@ -70,21 +99,21 @@ test_records = [ class TestBOM(unittest.TestCase): def test_get_items(self): from manufacturing.doctype.bom.bom import get_bom_items_as_dict - items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=0) - self.assertTrue(test_records[1][1]["item_code"] in items_dict) - self.assertTrue(test_records[1][2]["item_code"] in items_dict) + items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=0) + self.assertTrue(test_records[2][1]["item_code"] in items_dict) + self.assertTrue(test_records[2][2]["item_code"] in items_dict) self.assertEquals(len(items_dict.values()), 2) def test_get_items_exploded(self): from manufacturing.doctype.bom.bom import get_bom_items_as_dict - items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1) - self.assertTrue(test_records[1][1]["item_code"] in items_dict) - self.assertFalse(test_records[1][2]["item_code"] in items_dict) + items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1) + self.assertTrue(test_records[2][1]["item_code"] in items_dict) + self.assertFalse(test_records[2][2]["item_code"] in items_dict) self.assertTrue(test_records[0][1]["item_code"] in items_dict) self.assertTrue(test_records[0][2]["item_code"] in items_dict) self.assertEquals(len(items_dict.values()), 3) def test_get_items_list(self): from manufacturing.doctype.bom.bom import get_bom_items - self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1)), 3) + self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1)), 3) diff --git a/projects/doctype/time_log_batch/test_time_log_batch.py b/projects/doctype/time_log_batch/test_time_log_batch.py index 34a0cc06c9..4976dfe46d 100644 --- a/projects/doctype/time_log_batch/test_time_log_batch.py +++ b/projects/doctype/time_log_batch/test_time_log_batch.py @@ -5,15 +5,31 @@ import webnotes, unittest class TimeLogBatchTest(unittest.TestCase): def test_time_log_status(self): - self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted") - tlb = webnotes.bean("Time Log Batch", "_T-Time Log Batch-00001") + from projects.doctype.time_log.test_time_log import test_records as time_log_records + time_log = webnotes.bean(copy=time_log_records[0]) + time_log.doc.fields.update({ + "from_time": "2013-01-02 10:00:00", + "to_time": "2013-01-02 11:00:00", + "docstatus": 0 + }) + time_log.insert() + time_log.submit() + + self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted") + tlb = webnotes.bean(copy=test_records[0]) + tlb.doclist[1].time_log = time_log.doc.name + tlb.insert() tlb.submit() - self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Batched for Billing") + + self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Batched for Billing") tlb.cancel() - self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted") + self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted") test_records = [[ - {"rate": "500"}, + { + "doctype": "Time Log Batch", + "rate": "500" + }, { "doctype": "Time Log Batch Detail", "parenttype": "Time Log Batch", diff --git a/selling/doctype/customer/test_customer.py b/selling/doctype/customer/test_customer.py index 7c90f6a1a8..adc5a549ef 100644 --- a/selling/doctype/customer/test_customer.py +++ b/selling/doctype/customer/test_customer.py @@ -17,6 +17,8 @@ class TestCustomer(unittest.TestCase): (("_Test Customer 1 Renamed",),)) self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer 1"), ()) + webnotes.rename_doc("Customer", "_Test Customer 1 Renamed", "_Test Customer 1") + def test_merge(self): from webnotes.test_runner import make_test_records make_test_records("Sales Invoice") @@ -57,6 +59,9 @@ class TestCustomer(unittest.TestCase): # check that old name doesn't exist self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer"), ()) self.assertEqual(webnotes.conn.exists("Account", "_Test Customer - _TC"), ()) + + # create back _Test Customer + webnotes.bean(copy=test_records[0]).insert() test_ignore = ["Price List"] diff --git a/selling/doctype/quotation/test_quotation.py b/selling/doctype/quotation/test_quotation.py index cf3881d0c3..366035ef1a 100644 --- a/selling/doctype/quotation/test_quotation.py +++ b/selling/doctype/quotation/test_quotation.py @@ -11,17 +11,19 @@ class TestQuotation(unittest.TestCase): def test_make_sales_order(self): from selling.doctype.quotation.quotation import make_sales_order - self.assertRaises(webnotes.ValidationError, make_sales_order, "_T-Quotation-00001") + quotation = webnotes.bean(copy=test_records[0]) + quotation.insert() + + self.assertRaises(webnotes.ValidationError, make_sales_order, quotation.doc.name) - quotation = webnotes.bean("Quotation","_T-Quotation-00001") quotation.submit() - sales_order = make_sales_order("_T-Quotation-00001") + sales_order = make_sales_order(quotation.doc.name) self.assertEquals(sales_order[0]["doctype"], "Sales Order") self.assertEquals(len(sales_order), 2) self.assertEquals(sales_order[1]["doctype"], "Sales Order Item") - self.assertEquals(sales_order[1]["prevdoc_docname"], "_T-Quotation-00001") + self.assertEquals(sales_order[1]["prevdoc_docname"], quotation.doc.name) self.assertEquals(sales_order[0]["customer"], "_Test Customer") sales_order[0]["delivery_date"] = "2014-01-01" diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py index 8bd759a77d..0ee58a7fd2 100644 --- a/selling/doctype/sales_order/test_sales_order.py +++ b/selling/doctype/sales_order/test_sales_order.py @@ -72,6 +72,10 @@ class TestSalesOrder(unittest.TestCase): def create_dn_against_so(self, so, delivered_qty=0): from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records + from stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt + + _insert_purchase_receipt(so.doclist[1].item_code) + dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0])) dn.doclist[1].item_code = so.doclist[1].item_code dn.doclist[1].against_sales_order = so.doc.name @@ -272,14 +276,13 @@ class TestSalesOrder(unittest.TestCase): so.doclist[1].reserved_warehouse, 20.0) def test_warehouse_user(self): - webnotes.session.user = "test@example.com" - webnotes.bean("Profile", "test@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") webnotes.bean("Profile", "test2@example.com").get_controller()\ .add_roles("Sales User", "Sales Manager", "Material User", "Material Manager") - + + webnotes.session.user = "test@example.com" from stock.utils import UserNotAllowedForWarehouse so = webnotes.bean(copy = test_records[0]) diff --git a/stock/doctype/delivery_note/test_delivery_note.py b/stock/doctype/delivery_note/test_delivery_note.py index ca95a50602..2c4308bb42 100644 --- a/stock/doctype/delivery_note/test_delivery_note.py +++ b/stock/doctype/delivery_note/test_delivery_note.py @@ -9,20 +9,22 @@ import webnotes.defaults from webnotes.utils import cint from stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries, set_perpetual_inventory, test_records as pr_test_records +def _insert_purchase_receipt(item_code=None): + if not item_code: + item_code = pr_test_records[0][1]["item_code"] + + pr = webnotes.bean(copy=pr_test_records[0]) + pr.doclist[1].item_code = item_code + pr.insert() + pr.submit() + class TestDeliveryNote(unittest.TestCase): - def _insert_purchase_receipt(self, item_code=None): - pr = webnotes.bean(copy=pr_test_records[0]) - if item_code: - pr.doclist[1].item_code = item_code - pr.insert() - pr.submit() - def test_over_billing_against_dn(self): self.clear_stock_account_balance() - self._insert_purchase_receipt() + _insert_purchase_receipt() from stock.doctype.delivery_note.delivery_note import make_sales_invoice - self._insert_purchase_receipt() + _insert_purchase_receipt() dn = webnotes.bean(copy=test_records[0]).insert() self.assertRaises(webnotes.ValidationError, make_sales_invoice, @@ -44,7 +46,7 @@ class TestDeliveryNote(unittest.TestCase): set_perpetual_inventory(0) self.assertEqual(cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")), 0) - self._insert_purchase_receipt() + _insert_purchase_receipt() dn = webnotes.bean(copy=test_records[0]) dn.insert() @@ -69,7 +71,7 @@ class TestDeliveryNote(unittest.TestCase): self.assertEqual(cint(webnotes.defaults.get_global_default("auto_accounting_for_stock")), 1) webnotes.conn.set_value("Item", "_Test Item", "valuation_method", "FIFO") - self._insert_purchase_receipt() + _insert_purchase_receipt() dn = webnotes.bean(copy=test_records[0]) dn.doclist[1].expense_account = "Cost of Goods Sold - _TC" @@ -123,8 +125,8 @@ class TestDeliveryNote(unittest.TestCase): self.clear_stock_account_balance() set_perpetual_inventory() - self._insert_purchase_receipt() - self._insert_purchase_receipt("_Test Item Home Desktop 100") + _insert_purchase_receipt() + _insert_purchase_receipt("_Test Item Home Desktop 100") dn = webnotes.bean(copy=test_records[0]) dn.doclist[1].item_code = "_Test Sales BOM Item" diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index ad88c8cc8f..c8930abc97 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -81,9 +81,9 @@ test_records = [ "is_sales_item": "Yes", "is_service_item": "No", "inspection_required": "No", - "is_pro_applicable": "Yes", + "is_pro_applicable": "No", "is_sub_contracted_item": "No", - "is_manufactured_item": "Yes", + "is_manufactured_item": "No", "stock_uom": "_Test UOM" }, { @@ -109,6 +109,7 @@ test_records = [ "inspection_required": "No", "is_pro_applicable": "No", "is_sub_contracted_item": "No", + "is_manufactured_item": "No", "stock_uom": "_Test UOM" }], [{ @@ -207,4 +208,45 @@ test_records = [ "is_sub_contracted_item": "No", "stock_uom": "_Test UOM" }], + [{ + "doctype": "Item", + "item_code": "_Test Item Home Desktop Manufactured", + "item_name": "_Test Item Home Desktop Manufactured", + "description": "_Test Item Home Desktop Manufactured", + "item_group": "_Test Item Group Desktops", + "default_warehouse": "_Test Warehouse - _TC", + "default_income_account": "Sales - _TC", + "is_stock_item": "Yes", + "is_asset_item": "No", + "has_batch_no": "No", + "has_serial_no": "No", + "is_purchase_item": "Yes", + "is_sales_item": "Yes", + "is_service_item": "No", + "inspection_required": "No", + "is_pro_applicable": "Yes", + "is_sub_contracted_item": "No", + "is_manufactured_item": "Yes", + "stock_uom": "_Test UOM" + }], + [{ + "doctype": "Item", + "item_code": "_Test FG Item 2", + "item_name": "_Test FG Item 2", + "description": "_Test FG Item 2", + "item_group": "_Test Item Group Desktops", + "is_stock_item": "Yes", + "default_warehouse": "_Test Warehouse - _TC", + "default_income_account": "Sales - _TC", + "is_asset_item": "No", + "has_batch_no": "No", + "has_serial_no": "No", + "is_purchase_item": "Yes", + "is_sales_item": "Yes", + "is_service_item": "No", + "inspection_required": "No", + "is_pro_applicable": "Yes", + "is_sub_contracted_item": "Yes", + "stock_uom": "_Test UOM" + }], ] \ No newline at end of file diff --git a/support/doctype/newsletter/newsletter.py b/support/doctype/newsletter/newsletter.py index a6b5aa29e8..8e45768b35 100644 --- a/support/doctype/newsletter/newsletter.py +++ b/support/doctype/newsletter/newsletter.py @@ -76,14 +76,17 @@ class DocType(): sender = self.doc.send_from or webnotes.utils.get_formatted_email(self.doc.owner) from webnotes.utils.email_lib.bulk import send - webnotes.conn.auto_commit_on_many_writes = True + + if not webnotes.flags.in_test: + webnotes.conn.auto_commit_on_many_writes = True send(recipients = self.recipients, sender = sender, subject = self.doc.subject, message = self.doc.message, doctype = self.send_to_doctype, email_field = "email_id", ref_doctype = self.doc.doctype, ref_docname = self.doc.name) - webnotes.conn.auto_commit_on_many_writes = False + if not webnotes.flags.in_test: + webnotes.conn.auto_commit_on_many_writes = False def validate_send(self): if self.doc.fields.get("__islocal"): diff --git a/support/doctype/newsletter/test_newsletter.py b/support/doctype/newsletter/test_newsletter.py index fae3e40c49..3f4e021bb3 100644 --- a/support/doctype/newsletter/test_newsletter.py +++ b/support/doctype/newsletter/test_newsletter.py @@ -45,20 +45,23 @@ test_records =[ "subject": "_Test Newsletter to Lead", "send_to_type": "Lead", "lead_source": "All", - "message": "This is a test newsletter" + "message": "This is a test newsletter", + "send_from": "admin@example.com" }], [{ "doctype": "Newsletter", "subject": "_Test Newsletter to Contact", "send_to_type": "Contact", "contact_type": "Customer", - "message": "This is a test newsletter" + "message": "This is a test newsletter", + "send_from": "admin@example.com" }], [{ "doctype": "Newsletter", "subject": "_Test Newsletter to Custom", "send_to_type": "Custom", "email_list": "test_custom@example.com, test_custom1@example.com, test_custom2@example.com", - "message": "This is a test newsletter" + "message": "This is a test newsletter", + "send_from": "admin@example.com" }], ] diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 9df34c26ae..21da30b978 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -426,7 +426,7 @@ def import_data(dt, submit=False, overwrite=False): for doctype in dt: print "Importing", doctype.replace("_", " "), "..." - webnotes.form_dict = webnotes._dict() + webnotes.local.form_dict = webnotes._dict() if submit: webnotes.form_dict["params"] = json.dumps({"_submit": 1}) webnotes.uploaded_file = os.path.join(os.path.dirname(__file__), "demo_docs", doctype+".csv")