[merge] 4.x to 5.0
This commit is contained in:
commit
c68646c694
@ -1,5 +1,9 @@
|
||||
# Contributing to Frappe / ERPNext
|
||||
|
||||
### Update 16-Sep-14
|
||||
|
||||
Please send pull requests to branch v5.0
|
||||
|
||||
## Reporting issues
|
||||
|
||||
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.
|
||||
|
@ -232,7 +232,6 @@ cur_frm.fields_dict['entries'].grid.get_field('project_name').get_query = functi
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
|
||||
if(doc.select_print_heading){
|
||||
// print heading
|
||||
|
@ -142,6 +142,24 @@
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"description": "Start date of current invoice's period",
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "From Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"description": "End date of current invoice's period",
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "To Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
@ -752,12 +770,113 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.docstatus<2",
|
||||
"fieldname": "recurring_invoice",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Recurring Invoice",
|
||||
"options": "icon-time",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_77",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.docstatus<2",
|
||||
"description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date",
|
||||
"fieldname": "is_recurring",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Recurring",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "Select the period when the invoice will be generated automatically",
|
||||
"fieldname": "recurring_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Recurring Type",
|
||||
"no_copy": 1,
|
||||
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc",
|
||||
"fieldname": "repeat_on_day_of_month",
|
||||
"fieldtype": "Int",
|
||||
"label": "Repeat on Day of Month",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "The date on which next invoice will be generated. It is generated on submit.",
|
||||
"fieldname": "next_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Next Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "The date on which recurring invoice will be stop",
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_82",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "The unique id for tracking all recurring invoices. It is generated on submit.",
|
||||
"fieldname": "recurring_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Recurring Id",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"description": "Enter email id separated by commas, invoice will be mailed automatically on particular date",
|
||||
"fieldname": "notification_email_address",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Notification Email Address",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-09-09 05:35:32.156763",
|
||||
"modified": "2014-09-18 03:12:51.994059",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -4,11 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import cint, cstr, flt, formatdate
|
||||
|
||||
from frappe.utils import cint, cstr, formatdate, flt
|
||||
from frappe import msgprint, _, throw
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
|
||||
import frappe.defaults
|
||||
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
@ -49,6 +48,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_acc()
|
||||
self.clear_unallocated_advances("Purchase Invoice Advance", "advance_allocation_details")
|
||||
self.validate_advance_jv("advance_allocation_details", "purchase_order")
|
||||
self.check_for_acc_head_of_supplier()
|
||||
self.check_for_stopped_status()
|
||||
self.validate_with_previous_doc()
|
||||
@ -80,7 +80,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
def get_advances(self):
|
||||
super(PurchaseInvoice, self).get_advances(self.credit_to,
|
||||
"Purchase Invoice Advance", "advance_allocation_details", "debit")
|
||||
"Purchase Invoice Advance", "advance_allocation_details", "debit", "purchase_order")
|
||||
|
||||
def check_active_purchase_items(self):
|
||||
for d in self.get('entries'):
|
||||
@ -249,6 +249,8 @@ class PurchaseInvoice(BuyingController):
|
||||
reconcile_against_document(lst)
|
||||
|
||||
def on_submit(self):
|
||||
super(PurchaseInvoice, self).on_submit()
|
||||
|
||||
self.check_prev_docstatus()
|
||||
|
||||
frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype,
|
||||
|
@ -231,4 +231,8 @@ class TestPurchaseInvoice(unittest.TestCase):
|
||||
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
|
||||
where against_voucher=%s""", pi.name))
|
||||
|
||||
def test_recurring_invoice(self):
|
||||
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
||||
test_recurring_document(self, test_records)
|
||||
|
||||
test_records = frappe.get_test_records('Purchase Invoice')
|
||||
|
@ -399,37 +399,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
})
|
||||
}
|
||||
|
||||
cur_frm.cscript.is_recurring = function(doc, dt, dn) {
|
||||
// set default values for recurring invoices
|
||||
if(doc.is_recurring) {
|
||||
var owner_email = doc.owner=="Administrator"
|
||||
? frappe.user_info("Administrator").email
|
||||
: doc.owner;
|
||||
|
||||
doc.notification_email_address = $.map([cstr(owner_email),
|
||||
cstr(doc.contact_email)], function(v) { return v || null; }).join(", ");
|
||||
doc.repeat_on_day_of_month = frappe.datetime.str_to_obj(doc.posting_date).getDate();
|
||||
}
|
||||
|
||||
refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
|
||||
}
|
||||
|
||||
cur_frm.cscript.from_date = function(doc, dt, dn) {
|
||||
// set to_date
|
||||
if(doc.from_date) {
|
||||
var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
|
||||
'Yearly': 12};
|
||||
|
||||
var months = recurring_type_map[doc.recurring_type];
|
||||
if(months) {
|
||||
var to_date = frappe.datetime.add_months(doc.from_date,
|
||||
months);
|
||||
doc.to_date = frappe.datetime.add_days(to_date, -1);
|
||||
refresh_field('to_date');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.send_sms = function() {
|
||||
frappe.require("assets/erpnext/js/sms_manager.js");
|
||||
var sms_man = new SMSManager(cur_frm.doc);
|
||||
|
@ -174,7 +174,7 @@
|
||||
"description": "Start date of current invoice's period",
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "From",
|
||||
"label": "From Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
@ -186,7 +186,7 @@
|
||||
"description": "End date of current invoice's period",
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "To",
|
||||
"label": "To Date",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
@ -1192,7 +1192,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-09-09 05:35:34.121045",
|
||||
"modified": "2014-09-18 03:17:54.976732",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -4,18 +4,12 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
|
||||
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
|
||||
get_first_day, get_last_day
|
||||
from frappe.model.naming import make_autoname
|
||||
from frappe.utils import cint, cstr, flt
|
||||
from frappe import _, msgprint, throw
|
||||
|
||||
from erpnext.accounts.party import get_party_account, get_due_date
|
||||
from erpnext.controllers.stock_controller import update_gl_entries_after
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
from erpnext.controllers.recurring_document import *
|
||||
|
||||
from erpnext.controllers.selling_controller import SellingController
|
||||
|
||||
form_grid_templates = {
|
||||
@ -56,6 +50,7 @@ class SalesInvoice(SellingController):
|
||||
self.validate_debit_acc()
|
||||
self.validate_fixed_asset_account()
|
||||
self.clear_unallocated_advances("Sales Invoice Advance", "advance_adjustment_details")
|
||||
self.validate_advance_jv("advance_adjustment_details", "sales_order")
|
||||
self.add_remarks()
|
||||
|
||||
if cint(self.is_pos):
|
||||
@ -77,11 +72,12 @@ class SalesInvoice(SellingController):
|
||||
self.set_against_income_account()
|
||||
self.validate_c_form()
|
||||
self.validate_time_logs_are_submitted()
|
||||
validate_recurring_document(self)
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
|
||||
"delivery_note_details")
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesInvoice, self).on_submit()
|
||||
|
||||
if cint(self.update_stock) == 1:
|
||||
self.update_stock_ledger()
|
||||
else:
|
||||
@ -104,7 +100,6 @@ class SalesInvoice(SellingController):
|
||||
self.update_against_document_in_jv()
|
||||
|
||||
self.update_time_log_batch(self.name)
|
||||
convert_to_recurring(self, "RECINV.#####", self.posting_date)
|
||||
|
||||
def before_cancel(self):
|
||||
self.update_time_log_batch(None)
|
||||
@ -145,14 +140,6 @@ class SalesInvoice(SellingController):
|
||||
'overflow_type': 'delivery'
|
||||
})
|
||||
|
||||
def on_update_after_submit(self):
|
||||
validate_recurring_document(self)
|
||||
convert_to_recurring(self, "RECINV.#####", self.posting_date)
|
||||
|
||||
def before_recurring(self):
|
||||
self.aging_date = None
|
||||
self.due_date = None
|
||||
|
||||
def get_portal_page(self):
|
||||
return "invoice" if self.docstatus==1 else None
|
||||
|
||||
@ -222,7 +209,7 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def get_advances(self):
|
||||
super(SalesInvoice, self).get_advances(self.debit_to,
|
||||
"Sales Invoice Advance", "advance_adjustment_details", "credit")
|
||||
"Sales Invoice Advance", "advance_adjustment_details", "credit", "sales_order")
|
||||
|
||||
def get_company_abbr(self):
|
||||
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]
|
||||
@ -486,9 +473,8 @@ class SalesInvoice(SellingController):
|
||||
|
||||
if repost_future_gle and cint(self.update_stock) \
|
||||
and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||
items, warehouse_account = self.get_items_and_warehouse_accounts()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
warehouse_account, items)
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items)
|
||||
|
||||
def get_gl_entries(self, warehouse_account=None):
|
||||
from erpnext.accounts.general_ledger import merge_similar_entries
|
||||
|
@ -163,7 +163,7 @@ def create_party_account(party, party_type, company):
|
||||
|
||||
company_details = frappe.db.get_value("Company", company,
|
||||
["abbr", "receivables_group", "payables_group"], as_dict=True)
|
||||
if not frappe.db.exists("Account", (party + " - " + company_details.abbr)):
|
||||
if not frappe.db.exists("Account", (party.strip() + " - " + company_details.abbr)):
|
||||
parent_account = company_details.receivables_group \
|
||||
if party_type=="Customer" else company_details.payables_group
|
||||
if not parent_account:
|
||||
|
@ -21,7 +21,7 @@ class AccountsReceivableReport(object):
|
||||
def get_columns(self, customer_naming_by):
|
||||
columns = [
|
||||
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150",
|
||||
_("Voucher Type") + "::110", _("Voucher No") + "::120", "::30",
|
||||
_("Voucher Type") + "::110", _("Voucher No") + ":Dynamic Link/Voucher Type:120",
|
||||
_("Due Date") + ":Date:80",
|
||||
_("Invoiced Amount") + ":Currency:100", _("Payment Received") + ":Currency:100",
|
||||
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
|
||||
@ -63,11 +63,6 @@ class AccountsReceivableReport(object):
|
||||
|
||||
row += [self.get_territory(gle.account), gle.remarks]
|
||||
data.append(row)
|
||||
|
||||
for i in range(0, len(data)):
|
||||
data[i].insert(4, """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", data[i][2], data[i][3]]),))
|
||||
|
||||
return data
|
||||
|
||||
def get_entries_after(self, report_date):
|
||||
|
@ -9,29 +9,29 @@ from erpnext.stock.utils import get_buying_amount, get_sales_bom_buying_amount
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
|
||||
stock_ledger_entries = get_stock_ledger_entries(filters)
|
||||
source = get_source_data(filters)
|
||||
item_sales_bom = get_item_sales_bom()
|
||||
|
||||
columns = [_("Delivery Note/Sales Invoice") + "::120", _("Link") + "::30", _("Posting Date") + ":Date", _("Posting Time"),
|
||||
|
||||
columns = [_("Delivery Note/Sales Invoice") + "::120", _("Link") + "::30", _("Posting Date") + ":Date", _("Posting Time"),
|
||||
_("Item Code") + ":Link/Item", _("Item Name"), _("Description"), _("Warehouse") + ":Link/Warehouse",
|
||||
_("Qty") + ":Float", _("Selling Rate") + ":Currency", _("Avg. Buying Rate") + ":Currency",
|
||||
_("Qty") + ":Float", _("Selling Rate") + ":Currency", _("Avg. Buying Rate") + ":Currency",
|
||||
_("Selling Amount") + ":Currency", _("Buying Amount") + ":Currency",
|
||||
_("Gross Profit") + ":Currency", _("Gross Profit %") + ":Percent", _("Project") + ":Link/Project"]
|
||||
data = []
|
||||
for row in source:
|
||||
selling_amount = flt(row.base_amount)
|
||||
|
||||
|
||||
item_sales_bom_map = item_sales_bom.get(row.parenttype, {}).get(row.name, frappe._dict())
|
||||
|
||||
|
||||
if item_sales_bom_map.get(row.item_code):
|
||||
buying_amount = get_sales_bom_buying_amount(row.item_code, row.warehouse,
|
||||
buying_amount = get_sales_bom_buying_amount(row.item_code, row.warehouse,
|
||||
row.parenttype, row.name, row.item_row, stock_ledger_entries, item_sales_bom_map)
|
||||
else:
|
||||
buying_amount = get_buying_amount(row.item_code, row.qty, row.parenttype, row.name, row.item_row,
|
||||
stock_ledger_entries.get((row.item_code, row.warehouse), []))
|
||||
|
||||
|
||||
buying_amount = buying_amount > 0 and buying_amount or 0
|
||||
|
||||
gross_profit = selling_amount - buying_amount
|
||||
@ -39,41 +39,41 @@ def execute(filters=None):
|
||||
gross_profit_percent = (gross_profit / selling_amount) * 100.0
|
||||
else:
|
||||
gross_profit_percent = 0.0
|
||||
|
||||
|
||||
icon = """<a href="%s"><i class="icon icon-share" style="cursor: pointer;"></i></a>""" \
|
||||
% ("/".join(["#Form", row.parenttype, row.name]),)
|
||||
data.append([row.name, icon, row.posting_date, row.posting_time, row.item_code, row.item_name,
|
||||
row.description, row.warehouse, row.qty, row.base_rate,
|
||||
row.description, row.warehouse, row.qty, row.base_rate,
|
||||
row.qty and (buying_amount / row.qty) or 0, row.base_amount, buying_amount,
|
||||
gross_profit, gross_profit_percent, row.project])
|
||||
|
||||
|
||||
return columns, data
|
||||
|
||||
def get_stock_ledger_entries(filters):
|
||||
|
||||
def get_stock_ledger_entries(filters):
|
||||
query = """select item_code, voucher_type, voucher_no,
|
||||
voucher_detail_no, posting_date, posting_time, stock_value,
|
||||
warehouse, actual_qty as qty
|
||||
from `tabStock Ledger Entry`"""
|
||||
|
||||
|
||||
if filters.get("company"):
|
||||
query += """ where company=%(company)s"""
|
||||
|
||||
|
||||
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"
|
||||
|
||||
|
||||
res = frappe.db.sql(query, filters, as_dict=True)
|
||||
|
||||
|
||||
out = {}
|
||||
for r in res:
|
||||
if (r.item_code, r.warehouse) not in out:
|
||||
out[(r.item_code, r.warehouse)] = []
|
||||
|
||||
|
||||
out[(r.item_code, r.warehouse)].append(r)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def get_item_sales_bom():
|
||||
item_sales_bom = {}
|
||||
|
||||
|
||||
for d in frappe.db.sql("""select parenttype, parent, parent_item,
|
||||
item_code, warehouse, -1*qty as total_qty, parent_detail_docname
|
||||
from `tabPacked Item` where docstatus=1""", as_dict=True):
|
||||
@ -81,7 +81,7 @@ def get_item_sales_bom():
|
||||
frappe._dict()).setdefault(d.parent_item, []).append(d)
|
||||
|
||||
return item_sales_bom
|
||||
|
||||
|
||||
def get_source_data(filters):
|
||||
conditions = ""
|
||||
if filters.get("company"):
|
||||
@ -90,9 +90,9 @@ def get_source_data(filters):
|
||||
conditions += " and posting_date>=%(from_date)s"
|
||||
if filters.get("to_date"):
|
||||
conditions += " and posting_date<=%(to_date)s"
|
||||
|
||||
delivery_note_items = frappe.db.sql("""select item.parenttype, dn.name,
|
||||
dn.posting_date, dn.posting_time, dn.project_name,
|
||||
|
||||
delivery_note_items = frappe.db.sql("""select item.parenttype, dn.name,
|
||||
dn.posting_date, dn.posting_time, dn.project_name,
|
||||
item.item_code, item.item_name, item.description, item.warehouse,
|
||||
item.qty, item.base_rate, item.base_amount, item.name as "item_row",
|
||||
timestamp(dn.posting_date, dn.posting_time) as posting_datetime
|
||||
@ -100,7 +100,7 @@ def get_source_data(filters):
|
||||
where item.parent = dn.name and dn.docstatus = 1 %s
|
||||
order by dn.posting_date desc, dn.posting_time desc""" % (conditions,), filters, as_dict=1)
|
||||
|
||||
sales_invoice_items = frappe.db.sql("""select item.parenttype, si.name,
|
||||
sales_invoice_items = frappe.db.sql("""select item.parenttype, si.name,
|
||||
si.posting_date, si.posting_time, si.project_name,
|
||||
item.item_code, item.item_name, item.description, item.warehouse,
|
||||
item.qty, item.base_rate, item.base_amount, item.name as "item_row",
|
||||
@ -108,9 +108,9 @@ def get_source_data(filters):
|
||||
from `tabSales Invoice` si, `tabSales Invoice Item` item
|
||||
where item.parent = si.name and si.docstatus = 1 %s
|
||||
order by si.posting_date desc, si.posting_time desc""" % (conditions,), filters, as_dict=1)
|
||||
|
||||
|
||||
source = delivery_note_items + sales_invoice_items
|
||||
if len(source) > len(delivery_note_items):
|
||||
source.sort(key=lambda d: d.posting_datetime, reverse=True)
|
||||
|
||||
|
||||
return source
|
||||
|
@ -11,4 +11,4 @@ def execute(filters=None):
|
||||
conditions = get_columns(filters, "Sales Invoice")
|
||||
data = get_data(filters, conditions)
|
||||
|
||||
return conditions["columns"], data
|
||||
return conditions["columns"], data
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -162,6 +162,8 @@ class PurchaseOrder(BuyingController):
|
||||
msgprint(_("Status of {0} {1} is now {2}").format(self.doctype, self.name, status))
|
||||
|
||||
def on_submit(self):
|
||||
super(PurchaseOrder, self).on_submit()
|
||||
|
||||
purchase_controller = frappe.get_doc("Purchase Common")
|
||||
|
||||
self.update_prevdoc_status()
|
||||
|
@ -107,6 +107,10 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
po.get("po_details")[0].qty = 3.4
|
||||
self.assertRaises(UOMMustBeIntegerError, po.insert)
|
||||
|
||||
def test_recurring_order(self):
|
||||
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
|
||||
test_recurring_document(self, test_records)
|
||||
|
||||
|
||||
test_dependencies = ["BOM"]
|
||||
|
||||
|
@ -135,12 +135,6 @@ def get_data():
|
||||
"name": "Item-wise Purchase History",
|
||||
"doctype": "Item"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Item-wise Last Purchase Rate",
|
||||
"doctype": "Item"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
|
@ -26,6 +26,11 @@ def get_data():
|
||||
"name": "Purchase Receipt",
|
||||
"description": _("Goods received from Suppliers."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Installation Note",
|
||||
"description": _("Installation record for a Serial No.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Item",
|
||||
@ -57,11 +62,6 @@ def get_data():
|
||||
"name": "Stock Reconciliation",
|
||||
"description": _("Upload stock balance via csv.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Installation Note",
|
||||
"description": _("Installation record for a Serial No.")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Packing Slip",
|
||||
@ -171,6 +171,12 @@ def get_data():
|
||||
"label": _("Stock Analytics"),
|
||||
"icon": "icon-bar-chart"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Warehouse-Wise Stock Balance",
|
||||
"doctype": "Warehouse"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -222,12 +228,6 @@ def get_data():
|
||||
"name": "Batch-Wise Balance History",
|
||||
"doctype": "Batch"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Warehouse-Wise Stock Balance",
|
||||
"doctype": "Warehouse"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
|
@ -4,12 +4,11 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, throw
|
||||
from frappe.utils import add_days, cint, cstr, today, date_diff, flt, getdate, nowdate, \
|
||||
get_first_day, get_last_day
|
||||
from frappe.model.naming import make_autoname
|
||||
from frappe.utils import cint, today, flt
|
||||
from erpnext.setup.utils import get_company_currency, get_exchange_rate
|
||||
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
|
||||
from erpnext.utilities.transaction_base import TransactionBase
|
||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||
import json
|
||||
|
||||
class AccountsController(TransactionBase):
|
||||
@ -24,6 +23,24 @@ class AccountsController(TransactionBase):
|
||||
|
||||
self.validate_for_freezed_account()
|
||||
|
||||
if self.meta.get_field("is_recurring"):
|
||||
validate_recurring_document(self)
|
||||
|
||||
def on_submit(self):
|
||||
if self.meta.get_field("is_recurring"):
|
||||
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
|
||||
|
||||
def on_update_after_submit(self):
|
||||
if self.meta.get_field("is_recurring"):
|
||||
validate_recurring_document(self)
|
||||
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
|
||||
|
||||
def before_recurring(self):
|
||||
self.fiscal_year = None
|
||||
for fieldname in ("due_date", "aging_date"):
|
||||
if self.meta.get_field(fieldname):
|
||||
self.set(fieldname, None)
|
||||
|
||||
def set_missing_values(self, for_validate=False):
|
||||
for fieldname in ["posting_date", "transaction_date"]:
|
||||
if not self.get(fieldname) and self.meta.get_field(fieldname):
|
||||
@ -361,38 +378,67 @@ class AccountsController(TransactionBase):
|
||||
frappe.db.sql("""delete from `tab%s` where parentfield=%s and parent = %s
|
||||
and ifnull(allocated_amount, 0) = 0""" % (childtype, '%s', '%s'), (parentfield, self.name))
|
||||
|
||||
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr):
|
||||
against_order_list = []
|
||||
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr, against_order_field):
|
||||
so_list = list(set([d.get(against_order_field) for d in self.get("entries") if d.get(against_order_field)]))
|
||||
cond = ""
|
||||
if so_list:
|
||||
cond = "or (ifnull(t2.%s, '') in (%s))" % ("against_" + against_order_field, ', '.join(['%s']*len(so_list)))
|
||||
|
||||
res = frappe.db.sql("""
|
||||
select
|
||||
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no, t2.%s as order_no
|
||||
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no
|
||||
from
|
||||
`tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
|
||||
where
|
||||
t1.name = t2.parent and t2.account = %s and t2.is_advance = 'Yes' and t1.docstatus = 1
|
||||
and ifnull(t2.against_voucher, '') = ''
|
||||
and ifnull(t2.against_invoice, '') = ''
|
||||
and ifnull(t2.against_jv, '') = ''
|
||||
and ((
|
||||
ifnull(t2.against_voucher, '') = ''
|
||||
and ifnull(t2.against_invoice, '') = ''
|
||||
and ifnull(t2.against_jv, '') = ''
|
||||
and ifnull(t2.against_sales_order, '') = ''
|
||||
and ifnull(t2.against_purchase_order, '') = ''
|
||||
) %s)
|
||||
order by t1.posting_date""" %
|
||||
(dr_or_cr, "against_sales_order" if dr_or_cr == "credit" \
|
||||
else "against_purchase_order", '%s'),
|
||||
account_head, as_dict= True)
|
||||
|
||||
if self.get("entries"):
|
||||
for i in self.get("entries"):
|
||||
against_order_list.append(i.sales_order if dr_or_cr == "credit" else i.purchase_order)
|
||||
(dr_or_cr, '%s', cond),
|
||||
tuple([account_head] + so_list), as_dict= True)
|
||||
|
||||
self.set(parentfield, [])
|
||||
for d in res:
|
||||
if not against_order_list or d.order_no in against_order_list:
|
||||
self.append(parentfield, {
|
||||
"doctype": child_doctype,
|
||||
"journal_voucher": d.jv_no,
|
||||
"jv_detail_no": d.jv_detail_no,
|
||||
"remarks": d.remark,
|
||||
"advance_amount": flt(d.amount),
|
||||
"allocate_amount": 0
|
||||
})
|
||||
self.append(parentfield, {
|
||||
"doctype": child_doctype,
|
||||
"journal_voucher": d.jv_no,
|
||||
"jv_detail_no": d.jv_detail_no,
|
||||
"remarks": d.remark,
|
||||
"advance_amount": flt(d.amount),
|
||||
"allocate_amount": 0
|
||||
})
|
||||
|
||||
def validate_advance_jv(self, advance_table_fieldname, against_order_field):
|
||||
order_list = list(set([d.get(against_order_field) for d in self.get("entries") if d.get(against_order_field)]))
|
||||
if order_list:
|
||||
account = self.get("debit_to" if self.doctype=="Sales Invoice" else "credit_to")
|
||||
|
||||
jv_against_order = frappe.db.sql("""select parent, %s as against_order
|
||||
from `tabJournal Voucher Detail`
|
||||
where docstatus=1 and account=%s and ifnull(is_advance, 'No') = 'Yes'
|
||||
and ifnull(against_sales_order, '') in (%s)
|
||||
group by parent, against_sales_order""" %
|
||||
("against_" + against_order_field, '%s', ', '.join(['%s']*len(order_list))),
|
||||
tuple([account] + order_list), as_dict=1)
|
||||
|
||||
if jv_against_order:
|
||||
order_jv_map = {}
|
||||
for d in jv_against_order:
|
||||
order_jv_map.setdefault(d.against_order, []).append(d.parent)
|
||||
|
||||
advance_jv_against_si = [d.journal_voucher for d in self.get(advance_table_fieldname)]
|
||||
|
||||
for order, jv_list in order_jv_map.items():
|
||||
for jv in jv_list:
|
||||
if not advance_jv_against_si or jv not in advance_jv_against_si:
|
||||
frappe.throw(_("Journal Voucher {0} is linked against Order {1}, hence it must be fetched as advance in Invoice as well.")
|
||||
.format(jv, order))
|
||||
|
||||
|
||||
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||
from erpnext.controllers.status_updater import get_tolerance_for
|
||||
@ -420,7 +466,6 @@ class AccountsController(TransactionBase):
|
||||
max_allowed_amt = flt(ref_amt * (100 + tolerance) / 100)
|
||||
|
||||
if total_billed_amt - max_allowed_amt > 0.01:
|
||||
reduce_by = total_billed_amt - max_allowed_amt
|
||||
frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt))
|
||||
|
||||
def get_company_default(self, fieldname):
|
||||
|
@ -5,6 +5,7 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, msgprint
|
||||
from frappe.utils import flt, rounded
|
||||
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
from erpnext.accounts.party import get_party_details
|
||||
|
||||
|
@ -2,15 +2,28 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe.utils
|
||||
import frappe.defaults
|
||||
from frappe.utils import cint, cstr, getdate, nowdate, get_first_day, get_last_day
|
||||
|
||||
from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
|
||||
get_first_day, get_last_day, comma_and
|
||||
from frappe.model.naming import make_autoname
|
||||
|
||||
from frappe import _, msgprint, throw
|
||||
from erpnext.accounts.party import get_party_account, get_due_date, get_party_details
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
|
||||
date_field_map = {
|
||||
"Sales Order": "transaction_date",
|
||||
"Sales Invoice": "posting_date",
|
||||
"Purchase Order": "transaction_date",
|
||||
"Purchase Invoice": "posting_date"
|
||||
}
|
||||
|
||||
def create_recurring_documents():
|
||||
manage_recurring_documents("Sales Order")
|
||||
manage_recurring_documents("Sales Invoice")
|
||||
manage_recurring_documents("Purchase Order")
|
||||
manage_recurring_documents("Purchase Invoice")
|
||||
|
||||
def manage_recurring_documents(doctype, next_date=None, commit=True):
|
||||
"""
|
||||
@ -19,10 +32,7 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
|
||||
"""
|
||||
next_date = next_date or nowdate()
|
||||
|
||||
if doctype == "Sales Order":
|
||||
date_field = "transaction_date"
|
||||
elif doctype == "Sales Invoice":
|
||||
date_field = "posting_date"
|
||||
date_field = date_field_map[doctype]
|
||||
|
||||
recurring_documents = frappe.db.sql("""select name, recurring_id
|
||||
from `tab{}` where ifnull(is_recurring, 0)=1
|
||||
@ -51,7 +61,8 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
|
||||
frappe.db.sql("update `tab%s` \
|
||||
set is_recurring = 0 where name = %s" % (doctype, '%s'),
|
||||
(ref_document))
|
||||
notify_errors(ref_document, doctype, ref_wrapper.customer, ref_wrapper.owner)
|
||||
notify_errors(ref_document, doctype, ref_wrapper.get("customer") or ref_wrapper.get("supplier"),
|
||||
ref_wrapper.owner)
|
||||
frappe.db.commit()
|
||||
|
||||
exception_list.append(frappe.get_traceback())
|
||||
@ -118,7 +129,7 @@ def send_notification(new_rv):
|
||||
"fcontent": frappe.get_print_format(new_rv.doctype, new_rv.name, as_pdf=True)
|
||||
}])
|
||||
|
||||
def notify_errors(doc, doctype, customer, owner):
|
||||
def notify_errors(doc, doctype, party, owner):
|
||||
from frappe.utils.user import get_system_managers
|
||||
recipients = get_system_managers(only_name=True)
|
||||
|
||||
@ -127,7 +138,7 @@ def notify_errors(doc, doctype, customer, owner):
|
||||
message = frappe.get_template("templates/emails/recurring_document_failed.html").render({
|
||||
"type": doctype,
|
||||
"name": doc,
|
||||
"customer": customer
|
||||
"party": party
|
||||
}))
|
||||
|
||||
assign_task_to_owner(doc, doctype, "Recurring Invoice Failed", recipients)
|
||||
@ -155,18 +166,18 @@ def validate_recurring_document(doc):
|
||||
elif not (doc.from_date and doc.to_date):
|
||||
throw(_("Period From and Period To dates mandatory for recurring %s") % doc.doctype)
|
||||
|
||||
def convert_to_recurring(doc, autoname, posting_date):
|
||||
if doc.is_recurring:
|
||||
if not doc.recurring_id:
|
||||
frappe.db.set(doc, "recurring_id",
|
||||
make_autoname(autoname))
|
||||
#
|
||||
def convert_to_recurring(doc, posting_date):
|
||||
if doc.is_recurring:
|
||||
if not doc.recurring_id:
|
||||
frappe.db.set(doc, "recurring_id", doc.name)
|
||||
|
||||
set_next_date(doc, posting_date)
|
||||
set_next_date(doc, posting_date)
|
||||
|
||||
elif doc.recurring_id:
|
||||
frappe.db.sql("""update `tab%s`
|
||||
set is_recurring = 0
|
||||
where recurring_id = %s""" % (doc.doctype, '%s'), (doc.recurring_id))
|
||||
elif doc.recurring_id:
|
||||
frappe.db.sql("""update `tab%s` set is_recurring = 0
|
||||
where recurring_id = %s""" % (doc.doctype, '%s'), (doc.recurring_id))
|
||||
#
|
||||
|
||||
def validate_notification_email_id(doc):
|
||||
if doc.notification_email_address:
|
||||
|
@ -16,16 +16,15 @@ class StockController(AccountsController):
|
||||
delete_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||
|
||||
if cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
|
||||
warehouse_account = self.get_warehouse_account()
|
||||
warehouse_account = get_warehouse_account()
|
||||
|
||||
if self.docstatus==1:
|
||||
gl_entries = self.get_gl_entries(warehouse_account)
|
||||
make_gl_entries(gl_entries)
|
||||
|
||||
if repost_future_gle:
|
||||
items, warehouse_account = self.get_items_and_warehouse_accounts(warehouse_account)
|
||||
update_gl_entries_after(self.posting_date, self.posting_time,
|
||||
warehouse_account, items)
|
||||
items, warehouses = self.get_items_and_warehouses()
|
||||
update_gl_entries_after(self.posting_date, self.posting_time, warehouses, items, warehouse_account)
|
||||
|
||||
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
||||
default_cost_center=None):
|
||||
@ -88,10 +87,8 @@ class StockController(AccountsController):
|
||||
|
||||
return details
|
||||
|
||||
def get_items_and_warehouse_accounts(self, warehouse_account=None):
|
||||
def get_items_and_warehouses(self):
|
||||
items, warehouses = [], []
|
||||
if not warehouse_account:
|
||||
warehouse_account = get_warehouse_account()
|
||||
|
||||
if hasattr(self, "fname"):
|
||||
item_doclist = self.get(self.fname)
|
||||
@ -117,10 +114,7 @@ class StockController(AccountsController):
|
||||
if d.get("t_warehouse") and d.t_warehouse not in warehouses:
|
||||
warehouses.append(d.t_warehouse)
|
||||
|
||||
warehouse_account = {wh: warehouse_account[wh] for wh in warehouses
|
||||
if warehouse_account.get(wh)}
|
||||
|
||||
return items, warehouse_account
|
||||
return items, warehouses
|
||||
|
||||
def get_stock_ledger_details(self):
|
||||
stock_ledger = {}
|
||||
@ -130,73 +124,6 @@ class StockController(AccountsController):
|
||||
stock_ledger.setdefault(sle.voucher_detail_no, []).append(sle)
|
||||
return stock_ledger
|
||||
|
||||
def get_warehouse_account(self):
|
||||
warehouse_account = dict(frappe.db.sql("""select master_name, name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(master_name, '') != ''"""))
|
||||
return warehouse_account
|
||||
|
||||
def update_gl_entries_after(self, warehouse_account=None):
|
||||
future_stock_vouchers = self.get_future_stock_vouchers()
|
||||
gle = self.get_voucherwise_gl_entries(future_stock_vouchers)
|
||||
if not warehouse_account:
|
||||
warehouse_account = self.get_warehouse_account()
|
||||
for voucher_type, voucher_no in future_stock_vouchers:
|
||||
existing_gle = gle.get((voucher_type, voucher_no), [])
|
||||
voucher_obj = frappe.get_doc(voucher_type, voucher_no)
|
||||
expected_gle = voucher_obj.get_gl_entries(warehouse_account)
|
||||
if expected_gle:
|
||||
matched = True
|
||||
if existing_gle:
|
||||
for entry in expected_gle:
|
||||
for e in existing_gle:
|
||||
if entry.account==e.account \
|
||||
and entry.against_account==e.against_account\
|
||||
and entry.cost_center==e.cost_center:
|
||||
if entry.debit != e.debit or entry.credit != e.credit:
|
||||
matched = False
|
||||
break
|
||||
else:
|
||||
matched = False
|
||||
|
||||
if not matched:
|
||||
self.delete_gl_entries(voucher_type, voucher_no)
|
||||
voucher_obj.make_gl_entries(repost_future_gle=False)
|
||||
else:
|
||||
self.delete_gl_entries(voucher_type, voucher_no)
|
||||
|
||||
|
||||
def get_future_stock_vouchers(self):
|
||||
condition = ""
|
||||
item_list = []
|
||||
if getattr(self, "fname", None):
|
||||
item_list = [d.item_code for d in self.get(self.fname)]
|
||||
if item_list:
|
||||
condition = "and item_code in ({})".format(", ".join(["%s"] * len(item_list)))
|
||||
|
||||
future_stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||
from `tabStock Ledger Entry` sle
|
||||
where timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s) {condition}
|
||||
order by timestamp(sle.posting_date, sle.posting_time) asc, name asc""".format(
|
||||
condition=condition), tuple([self.posting_date, self.posting_date] + item_list),
|
||||
as_list=True)
|
||||
|
||||
return future_stock_vouchers
|
||||
|
||||
def get_voucherwise_gl_entries(self, future_stock_vouchers):
|
||||
gl_entries = {}
|
||||
if future_stock_vouchers:
|
||||
for d in frappe.db.sql("""select * from `tabGL Entry`
|
||||
where posting_date >= %s and voucher_no in (%s)""" %
|
||||
('%s', ', '.join(['%s']*len(future_stock_vouchers))),
|
||||
tuple([self.posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
|
||||
gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
|
||||
|
||||
return gl_entries
|
||||
|
||||
def delete_gl_entries(self, voucher_type, voucher_no):
|
||||
frappe.db.sql("""delete from `tabGL Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||
|
||||
def make_adjustment_entry(self, expected_gle, voucher_obj):
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
account_list = [d.account for d in expected_gle]
|
||||
@ -287,15 +214,15 @@ class StockController(AccountsController):
|
||||
|
||||
return serialized_items
|
||||
|
||||
def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None):
|
||||
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, warehouse_account=None):
|
||||
def _delete_gl_entries(voucher_type, voucher_no):
|
||||
frappe.db.sql("""delete from `tabGL Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||
|
||||
if not warehouse_account:
|
||||
warehouse_account = get_warehouse_account()
|
||||
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time,
|
||||
warehouse_account, for_items)
|
||||
|
||||
future_stock_vouchers = get_future_stock_vouchers(posting_date, posting_time, for_warehouses, for_items)
|
||||
gle = get_voucherwise_gl_entries(future_stock_vouchers, posting_date)
|
||||
|
||||
for voucher_type, voucher_no in future_stock_vouchers:
|
||||
@ -321,7 +248,7 @@ def compare_existing_and_expected_gle(existing_gle, expected_gle):
|
||||
break
|
||||
return matched
|
||||
|
||||
def get_future_stock_vouchers(posting_date, posting_time, warehouse_account=None, for_items=None):
|
||||
def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None):
|
||||
future_stock_vouchers = []
|
||||
|
||||
values = []
|
||||
@ -330,9 +257,9 @@ def get_future_stock_vouchers(posting_date, posting_time, warehouse_account=None
|
||||
condition += " and item_code in ({})".format(", ".join(["%s"] * len(for_items)))
|
||||
values += for_items
|
||||
|
||||
if warehouse_account:
|
||||
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(warehouse_account.keys())))
|
||||
values += warehouse_account.keys()
|
||||
if for_warehouses:
|
||||
condition += " and warehouse in ({})".format(", ".join(["%s"] * len(for_warehouses)))
|
||||
values += for_warehouses
|
||||
|
||||
for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||
from `tabStock Ledger Entry` sle
|
||||
|
@ -2,12 +2,8 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
import unittest, json, copy
|
||||
from frappe.utils import flt
|
||||
import frappe.permissions
|
||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
|
||||
from erpnext.controllers.recurring_document import date_field_map
|
||||
|
||||
def test_recurring_document(obj, test_records):
|
||||
from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate, add_days
|
||||
@ -27,20 +23,11 @@ def test_recurring_document(obj, test_records):
|
||||
"to_date": get_last_day(today)
|
||||
})
|
||||
|
||||
if base_doc.doctype == "Sales Order":
|
||||
base_doc.update({
|
||||
"transaction_date": today,
|
||||
"delivery_date": add_days(today, 15)
|
||||
})
|
||||
elif base_doc.doctype == "Sales Invoice":
|
||||
base_doc.update({
|
||||
"posting_date": today
|
||||
})
|
||||
date_field = date_field_map[base_doc.doctype]
|
||||
base_doc.set(date_field, today)
|
||||
|
||||
if base_doc.doctype == "Sales Order":
|
||||
date_field = "transaction_date"
|
||||
elif base_doc.doctype == "Sales Invoice":
|
||||
date_field = "posting_date"
|
||||
base_doc.set("delivery_date", add_days(today, 15))
|
||||
|
||||
# monthly
|
||||
doc1 = frappe.copy_doc(base_doc)
|
||||
@ -128,7 +115,7 @@ def _test_recurring_document(obj, base_doc, date_field, first_and_last_day):
|
||||
|
||||
next_date = get_next_date(base_doc.get(date_field), no_of_months,
|
||||
base_doc.repeat_on_day_of_month)
|
||||
|
||||
|
||||
manage_recurring_documents(base_doc.doctype, next_date=next_date, commit=False)
|
||||
|
||||
recurred_documents = frappe.db.sql("""select name from `tab%s`
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -96,7 +96,7 @@ cur_frm.cscript['Transfer Raw Materials'] = function() {
|
||||
}
|
||||
|
||||
cur_frm.cscript['Update Finished Goods'] = function() {
|
||||
cur_frm.cscript.make_se('Manufacture/Repack');
|
||||
cur_frm.cscript.make_se('Manufacture');
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['production_item'].get_query = function(doc) {
|
||||
|
@ -109,15 +109,15 @@
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"description": "Automatically updated via Stock Entry of type Manufacture/Repack",
|
||||
"fieldname": "produced_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Manufactured Qty",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "produced_qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"description": "Automatically updated via Stock Entry of type Manufacture or Repack",
|
||||
"fieldname": "produced_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Manufactured Qty",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "produced_qty",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ class ProductionOrder(Document):
|
||||
status = "Submitted"
|
||||
if stock_entries:
|
||||
status = "In Process"
|
||||
produced_qty = stock_entries.get("Manufacture/Repack")
|
||||
produced_qty = stock_entries.get("Manufacture")
|
||||
if flt(produced_qty) == flt(self.qty):
|
||||
status = "Completed"
|
||||
|
||||
@ -113,7 +113,7 @@ class ProductionOrder(Document):
|
||||
def update_produced_qty(self):
|
||||
produced_qty = frappe.db.sql("""select sum(fg_completed_qty)
|
||||
from `tabStock Entry` where production_order=%s and docstatus=1
|
||||
and purpose='Manufacture/Repack'""", self.name)
|
||||
and purpose='Manufacture'""", self.name)
|
||||
produced_qty = flt(produced_qty[0][0]) if produced_qty else 0
|
||||
|
||||
if produced_qty > self.qty:
|
||||
|
@ -31,7 +31,7 @@ class TestProductionOrder(unittest.TestCase):
|
||||
s.submit()
|
||||
|
||||
# from wip to fg
|
||||
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture/Repack", 4))
|
||||
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture", 4))
|
||||
s.insert()
|
||||
s.submit()
|
||||
|
||||
@ -49,7 +49,7 @@ class TestProductionOrder(unittest.TestCase):
|
||||
test_stock_entry.make_stock_entry("_Test Item", None, "_Test Warehouse - _TC", 100, 100)
|
||||
test_stock_entry.make_stock_entry("_Test Item Home Desktop 100", None, "_Test Warehouse - _TC", 100, 100)
|
||||
|
||||
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture/Repack", 7))
|
||||
s = frappe.get_doc(make_stock_entry(pro_doc.name, "Manufacture", 7))
|
||||
s.insert()
|
||||
|
||||
self.assertRaises(StockOverProductionError, s.submit)
|
||||
|
@ -6,12 +6,12 @@
|
||||
"doctype": "Report",
|
||||
"idx": 1,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2014-06-03 07:18:17.082436",
|
||||
"modified": "2014-09-17 12:41:55.740299",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Issued Items Against Production Order",
|
||||
"owner": "Administrator",
|
||||
"query": "select\n ste.production_order as \"Production Order:Link/Production Order:120\",\n ste.posting_date as \"Issue Date:Date:140\",\n ste_item.item_code as \"Item Code:Link/Item:120\",\n\tste_item.description as \"Description::150\",\n\tste_item.transfer_qty as \"Qty:Float:100\",\n\tste_item.stock_uom as \"UOM:Link/UOM:80\",\n\tste_item.amount as \"Amount:Currency:120\",\n\tste_item.serial_no as \"Serial No:Link/Serial No:80\",\n\tste_item.s_warehouse as \"Source Warehouse:Link/Warehouse:120\",\n\tste_item.t_warehouse as \"Target Warehouse:Link/Warehouse:120\",\n\tpro.production_item as \"Finished Goods:Link/Item:120\", \n\tste.name as \"Stock Entry:Link/Stock Entry:120\"\nfrom\n\t`tabStock Entry` ste, `tabStock Entry Detail` ste_item, `tabProduction Order` pro\nwhere\n\tifnull(ste.production_order, '') != '' and ste.name = ste_item.parent \n\tand ste.production_order = pro.name and ste.docstatus = 1 \n\tand ste.purpose = 'Manufacture/Repack'\norder by ste.posting_date, ste.production_order, ste_item.item_code",
|
||||
"query": "select\n ste.production_order as \"Production Order:Link/Production Order:120\",\n ste.posting_date as \"Issue Date:Date:140\",\n ste_item.item_code as \"Item Code:Link/Item:120\",\n\tste_item.description as \"Description::150\",\n\tste_item.transfer_qty as \"Qty:Float:100\",\n\tste_item.stock_uom as \"UOM:Link/UOM:80\",\n\tste_item.amount as \"Amount:Currency:120\",\n\tste_item.serial_no as \"Serial No:Link/Serial No:80\",\n\tste_item.s_warehouse as \"Source Warehouse:Link/Warehouse:120\",\n\tste_item.t_warehouse as \"Target Warehouse:Link/Warehouse:120\",\n\tpro.production_item as \"Finished Goods:Link/Item:120\", \n\tste.name as \"Stock Entry:Link/Stock Entry:120\"\nfrom\n\t`tabStock Entry` ste, `tabStock Entry Detail` ste_item, `tabProduction Order` pro\nwhere\n\tifnull(ste.production_order, '') != '' and ste.name = ste_item.parent \n\tand ste.production_order = pro.name and ste.docstatus = 1 \n\tand ste.purpose = 'Manufacture' or 'Repack'\norder by ste.posting_date, ste.production_order, ste_item.item_code",
|
||||
"ref_doctype": "Production Order",
|
||||
"report_name": "Issued Items Against Production Order",
|
||||
"report_type": "Query Report"
|
||||
|
@ -81,4 +81,5 @@ erpnext.patches.v4_2.default_website_style
|
||||
erpnext.patches.v4_2.set_company_country
|
||||
erpnext.patches.v4_2.update_sales_order_invoice_field_name
|
||||
erpnext.patches.v4_2.cost_of_production_cycle
|
||||
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
||||
erpnext.patches.v4_2.seprate_manufacture_and_repack
|
||||
erpnext.patches.v5_0.update_frozen_accounts_permission_role
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
warehouses_with_account = frappe.db.sql_list("""select master_name from tabAccount
|
||||
where ifnull(account_type, '') = 'Warehouse'""")
|
||||
|
||||
stock_vouchers_without_gle = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
|
||||
from `tabStock Ledger Entry` sle
|
||||
where sle.warehouse in (%s)
|
||||
and not exists(select name from `tabGL Entry`
|
||||
where voucher_type=sle.voucher_type and voucher_no=sle.voucher_no)
|
||||
order by sle.posting_date""" %
|
||||
', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
|
||||
|
||||
for voucher_type, voucher_no in stock_vouchers_without_gle:
|
||||
print voucher_type, voucher_no
|
||||
frappe.db.sql("""delete from `tabGL Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
|
||||
|
||||
voucher = frappe.get_doc(voucher_type, voucher_no)
|
||||
voucher.make_gl_entries()
|
||||
frappe.db.commit()
|
9
erpnext/patches/v4_2/seprate_manufacture_and_repack.py
Normal file
9
erpnext/patches/v4_2/seprate_manufacture_and_repack.py
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.db.sql("""update `tabStock Entry` set purpose='Manufacture' where purpose='Manufacture/Repack' and ifnull(production_order,"")!="" """)
|
||||
frappe.db.sql("""update `tabStock Entry` set purpose='Repack' where purpose='Manufacture/Repack' and ifnull(production_order,"")="" """)
|
@ -6,17 +6,17 @@ frappe.views.calendar["Task"] = {
|
||||
"start": "exp_start_date",
|
||||
"end": "exp_end_date",
|
||||
"id": "name",
|
||||
"title": __("subject"),
|
||||
"title": "subject",
|
||||
"allDay": "allDay"
|
||||
},
|
||||
gantt: true,
|
||||
filters: [
|
||||
{
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "project",
|
||||
"options": "Project",
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "project",
|
||||
"options": "Project",
|
||||
"label": __("Project")
|
||||
}
|
||||
],
|
||||
get_events_method: "erpnext.projects.doctype.task.task.get_events"
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ def get_columns():
|
||||
_("Cost of Issued Items") + ":Currency:160", _("Cost of Delivered Items") + ":Currency:160",
|
||||
_("Project Name") + "::120", _("Project Status") + "::120", _("Company") + ":Link/Company:100",
|
||||
_("Customer") + ":Link/Customer:140", _("Project Value") + ":Currency:120",
|
||||
_("Project Start Date") + ":Date:120", _("Completion Date") + ":Date:120"]+
|
||||
_("Project Start Date") + ":Date:120", _("Completion Date") + ":Date:120"]
|
||||
|
||||
def get_project_details():
|
||||
return frappe.db.sql(""" select name, project_name, status, company, customer, project_value,
|
||||
|
@ -24,7 +24,7 @@ var get_filters = function(){
|
||||
{ "value": "Item Group", "label": __("Item Group") },
|
||||
{ "value": "Supplier", "label": __("Supplier") },
|
||||
{ "value": "Supplier Type", "label": __("Supplier Type") },
|
||||
{ "value": "Supplier Type", "label": __("Project") }
|
||||
{ "value": "Project", "label": __("Project") }
|
||||
],
|
||||
"default": "Item"
|
||||
},
|
||||
|
@ -25,7 +25,7 @@ var get_filters = function(){
|
||||
{ "value": "Customer", "label": __("Customer") },
|
||||
{ "value": "Customer Group", "label": __("Customer Group") },
|
||||
{ "value": "Territory", "label": __("Territory") },
|
||||
{ "value": "Supplier Type", "label": __("Project") }
|
||||
{ "value": "Project", "label": __("Project") }
|
||||
],
|
||||
"default": "Item"
|
||||
},
|
||||
|
@ -155,7 +155,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
project_name: item.project_name || me.frm.doc.project_name
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
me.frm.script_manager.trigger("price_list_rate", cdt, cdn);
|
||||
@ -827,4 +827,35 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
|
||||
}
|
||||
},
|
||||
|
||||
is_recurring: function() {
|
||||
// set default values for recurring documents
|
||||
if(this.frm.doc.is_recurring) {
|
||||
var owner_email = this.frm.doc.owner=="Administrator"
|
||||
? frappe.user_info("Administrator").email
|
||||
: this.frm.doc.owner;
|
||||
|
||||
this.frm.doc.notification_email_address = $.map([cstr(owner_email),
|
||||
cstr(this.frm.doc.contact_email)], function(v) { return v || null; }).join(", ");
|
||||
this.frm.doc.repeat_on_day_of_month = frappe.datetime.str_to_obj(this.frm.doc.posting_date).getDate();
|
||||
}
|
||||
|
||||
refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
|
||||
},
|
||||
|
||||
from_date: function() {
|
||||
// set to_date
|
||||
if(this.frm.doc.from_date) {
|
||||
var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
|
||||
'Yearly': 12};
|
||||
|
||||
var months = recurring_type_map[this.frm.doc.recurring_type];
|
||||
if(months) {
|
||||
var to_date = frappe.datetime.add_months(this.frm.doc.from_date,
|
||||
months);
|
||||
this.frm.doc.to_date = frappe.datetime.add_days(to_date, -1);
|
||||
refresh_field('to_date');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -195,37 +195,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
}
|
||||
};
|
||||
|
||||
cur_frm.cscript.is_recurring = function(doc, dt, dn) {
|
||||
// set default values for recurring orders
|
||||
if(doc.is_recurring) {
|
||||
var owner_email = doc.owner=="Administrator"
|
||||
? frappe.user_info("Administrator").email
|
||||
: doc.owner;
|
||||
|
||||
doc.notification_email_address = $.map([cstr(owner_email),
|
||||
cstr(doc.contact_email)], function(v) { return v || null; }).join(", ");
|
||||
doc.repeat_on_day_of_month = frappe.datetime.str_to_obj(doc.posting_date).getDate();
|
||||
}
|
||||
|
||||
refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
|
||||
}
|
||||
|
||||
cur_frm.cscript.from_date = function(doc, dt, dn) {
|
||||
// set to_date
|
||||
if(doc.from_date) {
|
||||
var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
|
||||
'Yearly': 12};
|
||||
|
||||
var months = recurring_type_map[doc.recurring_type];
|
||||
if(months) {
|
||||
var to_date = frappe.datetime.add_months(doc.from_date,
|
||||
months);
|
||||
doc.to_date = frappe.datetime.add_days(to_date, -1);
|
||||
refresh_field('to_date');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.send_sms = function() {
|
||||
frappe.require("assets/erpnext/js/sms_manager.js");
|
||||
var sms_man = new SMSManager(cur_frm.doc);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,14 +4,10 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import frappe.utils
|
||||
|
||||
from frappe.utils import cstr, flt, getdate, comma_and
|
||||
|
||||
from frappe import _
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
|
||||
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
|
||||
|
||||
from erpnext.controllers.selling_controller import SellingController
|
||||
|
||||
form_grid_templates = {
|
||||
@ -122,8 +118,6 @@ class SalesOrder(SellingController):
|
||||
if not self.billing_status: self.billing_status = 'Not Billed'
|
||||
if not self.delivery_status: self.delivery_status = 'Not Delivered'
|
||||
|
||||
validate_recurring_document(self)
|
||||
|
||||
def validate_warehouse(self):
|
||||
from erpnext.stock.utils import validate_warehouse_company
|
||||
|
||||
@ -157,6 +151,8 @@ class SalesOrder(SellingController):
|
||||
doc.set_status(update=True)
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesOrder, self).on_submit()
|
||||
|
||||
self.update_stock_ledger(update_stock = 1)
|
||||
|
||||
self.check_credit(self.grand_total)
|
||||
@ -165,8 +161,6 @@ class SalesOrder(SellingController):
|
||||
|
||||
self.update_prevdoc_status('submit')
|
||||
frappe.db.set(self, 'status', 'Submitted')
|
||||
|
||||
convert_to_recurring(self, "SO/REC/.#####", self.transaction_date)
|
||||
|
||||
def on_cancel(self):
|
||||
# Cannot cancel stopped SO
|
||||
@ -255,11 +249,6 @@ class SalesOrder(SellingController):
|
||||
def get_portal_page(self):
|
||||
return "order" if self.docstatus==1 else None
|
||||
|
||||
def on_update_after_submit(self):
|
||||
validate_recurring_document(self)
|
||||
convert_to_recurring(self, "SO/REC/.#####", self.transaction_date)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_material_request(source_name, target_doc=None):
|
||||
def postprocess(source, doc):
|
||||
|
@ -7,34 +7,43 @@ from frappe import msgprint, _
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
|
||||
columns = get_columns(filters)
|
||||
data = get_entries(filters)
|
||||
|
||||
entries = get_entries(filters)
|
||||
item_details = get_item_details()
|
||||
data = []
|
||||
for d in entries:
|
||||
data.append([
|
||||
d.name, d.customer, d.territory, d.posting_date, d.item_code,
|
||||
item_details.get(d.item_code, {}).get("item_group"), item_details.get(d.item_code, {}).get("brand"),
|
||||
d.qty, d.base_amount, d.sales_person, d.allocated_percentage, d.contribution_amt
|
||||
])
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns(filters):
|
||||
if not filters.get("doc_type"):
|
||||
msgprint(_("Please select the document type first"), raise_exception=1)
|
||||
|
||||
return [filters["doc_type"] + ":Link/" + filters["doc_type"] + ":140",
|
||||
_("Customer") + ":Link/Customer:140", _("Territory") + ":Link/Territory:100", _("Posting Date") + ":Date:100",
|
||||
_("Item Code") + ":Link/Item:120", _("Qty") + ":Float:100", _("Amount") + ":Currency:120",
|
||||
_("Sales Person") + ":Link/Sales Person:140", _("Contribution %") + ":Float:110",
|
||||
|
||||
return [filters["doc_type"] + ":Link/" + filters["doc_type"] + ":140",
|
||||
_("Customer") + ":Link/Customer:140", _("Territory") + ":Link/Territory:100", _("Posting Date") + ":Date:100",
|
||||
_("Item Code") + ":Link/Item:120", _("Item Group") + ":Link/Item Group:120",
|
||||
_("Brand") + ":Link/Brand:120", _("Qty") + ":Float:100", _("Amount") + ":Currency:120",
|
||||
_("Sales Person") + ":Link/Sales Person:140", _("Contribution %") + ":Float:110",
|
||||
_("Contribution Amount") + ":Currency:140"]
|
||||
|
||||
|
||||
def get_entries(filters):
|
||||
date_field = filters["doc_type"] == "Sales Order" and "transaction_date" or "posting_date"
|
||||
conditions, items = get_conditions(filters, date_field)
|
||||
entries = frappe.db.sql("""select dt.name, dt.customer, dt.territory, dt.%s,
|
||||
dt_item.item_code, dt_item.qty, dt_item.base_amount, st.sales_person,
|
||||
st.allocated_percentage, dt_item.base_amount*st.allocated_percentage/100
|
||||
from `tab%s` dt, `tab%s Item` dt_item, `tabSales Team` st
|
||||
where st.parent = dt.name and dt.name = dt_item.parent and st.parenttype = %s
|
||||
and dt.docstatus = 1 %s order by st.sales_person, dt.name desc""" %
|
||||
(date_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
|
||||
tuple([filters["doc_type"]] + items), as_list=1)
|
||||
|
||||
entries = frappe.db.sql("""select dt.name, dt.customer, dt.territory, dt.%s as posting_date,
|
||||
dt_item.item_code, dt_item.qty, dt_item.base_amount, st.sales_person,
|
||||
st.allocated_percentage, dt_item.base_amount*st.allocated_percentage/100 as contribution_amt
|
||||
from `tab%s` dt, `tab%s Item` dt_item, `tabSales Team` st
|
||||
where st.parent = dt.name and dt.name = dt_item.parent and st.parenttype = %s
|
||||
and dt.docstatus = 1 %s order by st.sales_person, dt.name desc""" %
|
||||
(date_field, filters["doc_type"], filters["doc_type"], '%s', conditions),
|
||||
tuple([filters["doc_type"]] + items), as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
def get_conditions(filters, date_field):
|
||||
@ -45,18 +54,18 @@ def get_conditions(filters, date_field):
|
||||
filters["customer"].replace("'", "\'")
|
||||
if filters.get("territory"): conditions += " and dt.territory = '%s'" % \
|
||||
filters["territory"].replace("'", "\'")
|
||||
|
||||
|
||||
if filters.get("from_date"): conditions += " and dt.%s >= '%s'" % \
|
||||
(date_field, filters["from_date"])
|
||||
if filters.get("to_date"): conditions += " and dt.%s <= '%s'" % (date_field, filters["to_date"])
|
||||
|
||||
|
||||
if filters.get("sales_person"): conditions += " and st.sales_person = '%s'" % \
|
||||
filters["sales_person"].replace("'", "\'")
|
||||
|
||||
|
||||
items = get_items(filters)
|
||||
if items:
|
||||
conditions += " and dt_item.item_code in (%s)" % ', '.join(['%s']*len(items))
|
||||
|
||||
|
||||
return conditions, items
|
||||
|
||||
def get_items(filters):
|
||||
@ -66,7 +75,14 @@ def get_items(filters):
|
||||
|
||||
items = []
|
||||
if key:
|
||||
items = frappe.db.sql_list("""select name from tabItem where %s = %s""" %
|
||||
items = frappe.db.sql_list("""select name from tabItem where %s = %s""" %
|
||||
(key, '%s'), (filters[key]))
|
||||
|
||||
return items
|
||||
|
||||
return items
|
||||
|
||||
def get_item_details():
|
||||
item_details = {}
|
||||
for d in frappe.db.sql("""select name, item_group, brand from `tabItem`""", as_dict=1):
|
||||
item_details.setdefault(d.name, d)
|
||||
|
||||
return item_details
|
||||
|
@ -3,19 +3,11 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import cstr, flt, has_common, make_esc, comma_or
|
||||
|
||||
from frappe.utils import cstr, flt, has_common, comma_or
|
||||
from frappe import session, _
|
||||
|
||||
|
||||
from erpnext.utilities.transaction_base import TransactionBase
|
||||
|
||||
class AuthorizationControl(TransactionBase):
|
||||
|
||||
|
||||
# Get Names of all Approving Users and Roles
|
||||
# -------------------------------------------
|
||||
def get_appr_user_role(self, det, doctype_name, total, based_on, condition, item, company):
|
||||
amt_list, appr_users, appr_roles = [], [], []
|
||||
users, roles = '',''
|
||||
@ -24,10 +16,18 @@ class AuthorizationControl(TransactionBase):
|
||||
amt_list.append(flt(x[0]))
|
||||
max_amount = max(amt_list)
|
||||
|
||||
app_dtl = frappe.db.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 = frappe.db.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 = frappe.db.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 = frappe.db.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])
|
||||
@ -36,43 +36,56 @@ class AuthorizationControl(TransactionBase):
|
||||
frappe.msgprint(_("Not authroized since {0} exceeds limits").format(_(based_on)))
|
||||
frappe.throw(_("Can be approved by {0}").format(comma_or(appr_roles + appr_users)))
|
||||
|
||||
|
||||
# Check if authorization rule is set specific to user
|
||||
# ----------------------------------------------------
|
||||
def validate_auth_rule(self, doctype_name, total, based_on, cond, company, item = ''):
|
||||
chk = 1
|
||||
add_cond1,add_cond2 = '',''
|
||||
if based_on == 'Itemwise Discount':
|
||||
add_cond1 += " and master_name = '"+cstr(item)+"'"
|
||||
itemwise_exists = frappe.db.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))
|
||||
add_cond1 += " and master_name = '"+cstr(item).replace("'", "\\'")+"'"
|
||||
itemwise_exists = frappe.db.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 = frappe.db.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 = frappe.db.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 = frappe.db.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 based_on == 'Itemwise Discount':
|
||||
add_cond2 += " and ifnull(master_name,'') = ''"
|
||||
|
||||
appr = frappe.db.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 = frappe.db.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 = frappe.db.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)
|
||||
|
||||
|
||||
# Bifurcate Authorization based on type
|
||||
# --------------------------------------
|
||||
def bifurcate_based_on_type(self, doctype_name, total, av_dis, based_on, doc_obj, val, company):
|
||||
add_cond = ''
|
||||
auth_value = av_dis
|
||||
if val == 1: add_cond += " and system_user = '"+session['user']+"'"
|
||||
|
||||
if val == 1: add_cond += " and system_user = '"+session['user'].replace("'", "\\'")+"'"
|
||||
elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.user.get_roles())+"')")
|
||||
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
|
||||
|
||||
if based_on == 'Grand Total': auth_value = total
|
||||
elif based_on == 'Customerwise Discount':
|
||||
if doc_obj:
|
||||
if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
|
||||
else: customer = doc_obj.customer_name
|
||||
add_cond = " and master_name = '"+make_esc("'")(cstr(customer))+"'"
|
||||
add_cond = " and master_name = '"+cstr(customer).replace("'", "\\'")+"'"
|
||||
if based_on == 'Itemwise Discount':
|
||||
if doc_obj:
|
||||
for t in doc_obj.get(doc_obj.fname):
|
||||
@ -80,9 +93,6 @@ class AuthorizationControl(TransactionBase):
|
||||
else:
|
||||
self.validate_auth_rule(doctype_name, auth_value, based_on, add_cond, company)
|
||||
|
||||
|
||||
# Check Approving Authority for transactions other than expense voucher and Appraisal
|
||||
# -------------------------
|
||||
def validate_approving_authority(self, doctype_name,company, total, doc_obj = ''):
|
||||
av_dis = 0
|
||||
if doc_obj:
|
||||
@ -94,11 +104,12 @@ class AuthorizationControl(TransactionBase):
|
||||
if price_list_rate: av_dis = 100 - flt(base_rate * 100 / price_list_rate)
|
||||
|
||||
final_based_on = ['Grand Total','Average Discount','Customerwise Discount','Itemwise Discount']
|
||||
# Individual User
|
||||
# ================
|
||||
# Check for authorization set for individual user
|
||||
|
||||
based_on = [x[0] for x in frappe.db.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))]
|
||||
# Check for authorization set for individual user
|
||||
based_on = [x[0] for x in frappe.db.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)
|
||||
@ -107,8 +118,6 @@ class AuthorizationControl(TransactionBase):
|
||||
for r in based_on:
|
||||
if r in final_based_on and r != 'Itemwise Discount': final_based_on.remove(r)
|
||||
|
||||
# Specific Role
|
||||
# ===============
|
||||
# Check for authorization set on particular roles
|
||||
based_on = [x[0] for x in frappe.db.sql("""select based_on
|
||||
from `tabAuthorization Rule`
|
||||
@ -124,19 +133,24 @@ class AuthorizationControl(TransactionBase):
|
||||
for r in based_on:
|
||||
if r in final_based_on and r != 'Itemwise Discount': final_based_on.remove(r)
|
||||
|
||||
# Global Rule
|
||||
# =============
|
||||
# Check for global authorization
|
||||
for g in final_based_on:
|
||||
self.bifurcate_based_on_type(doctype_name, total, av_dis, g, doc_obj, 0, company)
|
||||
|
||||
#========================================================================================================================
|
||||
# payroll related check
|
||||
def get_value_based_rule(self,doctype_name,employee,total_claimed_amount,company):
|
||||
val_lst =[]
|
||||
val = frappe.db.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 = frappe.db.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 = frappe.db.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 = frappe.db.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]
|
||||
@ -144,13 +158,23 @@ class AuthorizationControl(TransactionBase):
|
||||
val_lst.append(0)
|
||||
|
||||
max_val = max(val_lst)
|
||||
rule = frappe.db.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 = frappe.db.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 = frappe.db.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 = frappe.db.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
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------
|
||||
# related to payroll module only
|
||||
def get_approver_name(self, doctype_name, total, doc_obj=''):
|
||||
app_user=[]
|
||||
@ -159,11 +183,22 @@ class AuthorizationControl(TransactionBase):
|
||||
|
||||
if doc_obj:
|
||||
if doctype_name == 'Expense Claim':
|
||||
rule = self.get_value_based_rule(doctype_name,doc_obj.employee,doc_obj.total_claimed_amount, doc_obj.company)
|
||||
rule = self.get_value_based_rule(doctype_name, doc_obj.employee,
|
||||
doc_obj.total_claimed_amount, doc_obj.company)
|
||||
elif doctype_name == 'Appraisal':
|
||||
rule = frappe.db.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.employee, doc_obj.employee, doc_obj.company),as_dict=1)
|
||||
rule = frappe.db.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.employee, doc_obj.employee, doc_obj.company),as_dict=1)
|
||||
|
||||
if not rule:
|
||||
rule = frappe.db.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.employee, doc_obj.employee),as_dict=1)
|
||||
rule = frappe.db.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.employee, doc_obj.employee), as_dict=1)
|
||||
|
||||
if rule:
|
||||
for m in rule:
|
||||
@ -171,7 +206,11 @@ class AuthorizationControl(TransactionBase):
|
||||
if m['approving_user']:
|
||||
app_specific_user.append(m['approving_user'])
|
||||
elif m['approving_role']:
|
||||
user_lst = [z[0] for z in frappe.db.sql("select distinct t1.name from `tabUser` 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 frappe.db.sql("""select distinct t1.name
|
||||
from `tabUser` 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)
|
||||
|
@ -1,19 +1,6 @@
|
||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
cur_frm.cscript.get_states=function(doc, dt, dn) {
|
||||
return $c('runserverobj', args={'method': 'check_state', 'docs':doc},
|
||||
function(r, rt) {
|
||||
if(r.message)
|
||||
set_field_options('state', r.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
cur_frm.cscript.country = function(doc, dt, dn) {
|
||||
cur_frm.cscript.get_states(doc, dt, dn);
|
||||
}
|
||||
|
||||
if(cur_frm.fields_dict['territory']) {
|
||||
cur_frm.fields_dict['territory'].get_query = function(doc, dt, dn) {
|
||||
return {
|
||||
|
@ -73,7 +73,7 @@ cur_frm.cscript.addremove_recipients = function(doc, dt, dn) {
|
||||
var fullname = frappe.user.full_name(v.name);
|
||||
if(fullname !== v.name) v.name = fullname + " <" + v.name + ">";
|
||||
if(v.enabled==0) {
|
||||
v.name = repl("<span style='color: red'> %(name)s (disabled user)</span>", {name: v.name});
|
||||
v.name = repl("<span style='color: red'> %(name)s (" + __("disabled user") + ")</span>", {name: v.name});
|
||||
}
|
||||
var user = $a($td(tab, i+1, 1), 'span', '', '', v.name);
|
||||
//user.onclick = function() { check.checked = !check.checked; }
|
||||
@ -81,11 +81,11 @@ cur_frm.cscript.addremove_recipients = function(doc, dt, dn) {
|
||||
|
||||
// Display add recipients button
|
||||
if(r.user_list.length>15) {
|
||||
$btn($td(tab, 0, 1), add_or_update + ' Recipients', function() {
|
||||
$btn($td(tab, 0, 1), __('{0} Recipients',[__(add_or_update)]), function() {
|
||||
cur_frm.cscript.add_to_rec_list(doc, tab, r.user_list.length);
|
||||
});
|
||||
}
|
||||
$btn($td(tab, r.user_list.length+1, 1), add_or_update + ' Recipients', function() {
|
||||
$btn($td(tab, r.user_list.length+1, 1),__('{0} Recipients',[__(add_or_update)]), function() {
|
||||
cur_frm.cscript.add_to_rec_list(doc, tab, r.user_list.length);
|
||||
});
|
||||
|
||||
|
@ -128,7 +128,7 @@ class EmailDigest(Document):
|
||||
with_value = "\n".join(with_value)
|
||||
else:
|
||||
has_updates = False
|
||||
with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
|
||||
with_value = "<p>" + _("There were no updates in the items selected for this digest.") + "</p><hr>"
|
||||
|
||||
if not has_updates and send_only_if_updates:
|
||||
return
|
||||
@ -136,7 +136,7 @@ class EmailDigest(Document):
|
||||
# seperate out no value items
|
||||
no_value = [o[1] for o in out if not o[0]]
|
||||
if no_value:
|
||||
no_value = """<h4>No Updates For:</h4>""" + "\n".join(no_value)
|
||||
no_value = """<h4>""" + _("No Updates For") + """:</h4>""" + "\n".join(no_value)
|
||||
|
||||
date = self.frequency == "Daily" and formatdate(self.from_date) or \
|
||||
"%s to %s" % (formatdate(self.from_date), formatdate(self.to_date))
|
||||
@ -310,9 +310,9 @@ class EmailDigest(Document):
|
||||
(e.subject, datetime_in_user_format(e.starts_on), datetime_in_user_format(e.ends_on))
|
||||
|
||||
if html:
|
||||
return 1, "<h4>Upcoming Calendar Events (max 10):</h4><ul>" + html + "</ul><hr>"
|
||||
return 1, "<h4>" + _("Upcoming Calendar Events (max 10)") + ":</h4><ul>" + html + "</ul><hr>"
|
||||
else:
|
||||
return 0, "<p>Calendar Events</p>"
|
||||
return 0, "<p>" + _("Calendar Events") + "</p>"
|
||||
|
||||
def get_todo_list(self, user_id):
|
||||
todo_list = frappe.db.sql("""select *
|
||||
|
@ -60,11 +60,10 @@ class NamingSeries(Document):
|
||||
# validate names
|
||||
for i in options: self.validate_series_name(i)
|
||||
|
||||
if self.user_must_always_select:
|
||||
if options and self.user_must_always_select:
|
||||
options = [''] + options
|
||||
default = ''
|
||||
else:
|
||||
default = options[0]
|
||||
|
||||
default = options[0] if options else ''
|
||||
|
||||
# update in property setter
|
||||
prop_dict = {'options': "\n".join(options), 'default': default}
|
||||
|
@ -3,8 +3,15 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
class Batch(Document):
|
||||
pass
|
||||
|
||||
def validate(self):
|
||||
self.item_has_batch_enabled()
|
||||
|
||||
def item_has_batch_enabled(self):
|
||||
has_batch_no = frappe.db.get_value("Item",self.item,"has_batch_no")
|
||||
if has_batch_no =='No':
|
||||
frappe.throw(_("The selected item cannot have Batch"))
|
14
erpnext/stock/doctype/batch/test_batch.py
Normal file
14
erpnext/stock/doctype/batch/test_batch.py
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.exceptions import ValidationError
|
||||
import unittest
|
||||
|
||||
class TestBatch(unittest.TestCase):
|
||||
def test_item_has_batch_enabled(self):
|
||||
self.assertRaises(ValidationError, frappe.get_doc({
|
||||
"doctype": "Batch",
|
||||
"name": "_test Batch",
|
||||
"item": "_Test Item"
|
||||
}).save)
|
@ -19,7 +19,7 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
cur_frm.cscript.edit_prices_button();
|
||||
|
||||
if (!doc.__islocal && doc.is_stock_item == 'Yes') {
|
||||
cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'],
|
||||
cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method', 'has_batch_no'],
|
||||
(doc.__onload && doc.__onload.sle_exists=="exists") ? false : true);
|
||||
}
|
||||
|
||||
@ -185,4 +185,4 @@ cur_frm.cscript.image = function() {
|
||||
else {
|
||||
msgprint(__("You may need to update: {0}", [frappe.meta.get_docfield(cur_frm.doc.doctype, "description_html").label]));
|
||||
}
|
||||
}
|
||||
}
|
@ -187,13 +187,14 @@ class Item(WebsiteGenerator):
|
||||
def cant_change(self):
|
||||
if not self.get("__islocal"):
|
||||
vals = frappe.db.get_value("Item", self.name,
|
||||
["has_serial_no", "is_stock_item", "valuation_method"], as_dict=True)
|
||||
["has_serial_no", "is_stock_item", "valuation_method", "has_batch_no"], as_dict=True)
|
||||
|
||||
if vals and ((self.is_stock_item == "No" and vals.is_stock_item == "Yes") or
|
||||
vals.has_serial_no != self.has_serial_no or
|
||||
vals.has_batch_no != self.has_batch_no or
|
||||
cstr(vals.valuation_method) != cstr(self.valuation_method)):
|
||||
if self.check_if_sle_exists() == "exists":
|
||||
frappe.throw(_("As there are existing stock transactions for this item, you can not change the values of 'Has Serial No', 'Is Stock Item' and 'Valuation Method'"))
|
||||
frappe.throw(_("As there are existing stock transactions for this item, you can not change the values of 'Has Serial No', 'Has Batch No', 'Is Stock Item' and 'Valuation Method'"))
|
||||
|
||||
def validate_item_type_for_reorder(self):
|
||||
if self.re_order_level or len(self.get("item_reorder", {"material_request_type": "Purchase"})):
|
||||
|
@ -1,5 +1,5 @@
|
||||
frappe.listview_settings['Item'] = {
|
||||
add_fields: ["item_name", "stock_uom", "item_group", "image",
|
||||
"is_stock_item", "is_sales_item", "is_purchase_item",
|
||||
"is_manufactured_item", "show_in_website"]
|
||||
add_fields: ["`tabItem`.`item_name`", "`tabItem`.`stock_uom`", "`tabItem`.`item_group`", "`tabItem`.`image`",
|
||||
"`tabItem`.`is_stock_item`", "`tabItem`.`is_sales_item`", "`tabItem`.`is_purchase_item`",
|
||||
"`tabItem`.`is_manufactured_item`", "`tabItem`.`show_in_website`"]
|
||||
};
|
||||
|
@ -9,6 +9,6 @@ class TestItem(unittest.TestCase):
|
||||
def test_duplicate_item(self):
|
||||
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
|
||||
doc = frappe.copy_doc(test_records[0])
|
||||
self.assertRaises(ItemPriceDuplicateItem, doc.insert)
|
||||
self.assertRaises(ItemPriceDuplicateItem, doc.save)
|
||||
|
||||
test_records = frappe.get_test_records('Item Price')
|
@ -15,7 +15,7 @@ class LandedCostVoucher(Document):
|
||||
self.set("landed_cost_items", [])
|
||||
for pr in self.get("landed_cost_purchase_receipts"):
|
||||
pr_items = frappe.db.sql("""select pr_item.item_code, pr_item.description,
|
||||
pr_item.qty, pr_item.rate, pr_item.amount, pr_item.name
|
||||
pr_item.qty, pr_item.base_rate, pr_item.base_amount, pr_item.name
|
||||
from `tabPurchase Receipt Item` pr_item where parent = %s
|
||||
and exists(select name from tabItem where name = pr_item.item_code and is_stock_item = 'Yes')""",
|
||||
pr.purchase_receipt, as_dict=True)
|
||||
@ -25,8 +25,8 @@ class LandedCostVoucher(Document):
|
||||
item.item_code = d.item_code
|
||||
item.description = d.description
|
||||
item.qty = d.qty
|
||||
item.rate = d.rate
|
||||
item.amount = d.amount
|
||||
item.rate = d.base_rate
|
||||
item.amount = d.base_amount
|
||||
item.purchase_receipt = pr.purchase_receipt
|
||||
item.purchase_receipt_item = d.name
|
||||
|
||||
|
@ -120,7 +120,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
clean_up: function() {
|
||||
// Clear Production Order record from locals, because it is updated via Stock Entry
|
||||
if(this.frm.doc.production_order &&
|
||||
this.frm.doc.purpose == "Manufacture/Repack") {
|
||||
this.frm.doc.purpose == "Manufacture") {
|
||||
frappe.model.remove_from_locals("Production Order",
|
||||
this.frm.doc.production_order);
|
||||
}
|
||||
@ -162,7 +162,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
},
|
||||
|
||||
toggle_enable_bom: function() {
|
||||
this.frm.toggle_enable("bom_no", !this.frm.doc.production_order);
|
||||
this.frm.toggle_enable("bom_no", this.frm.doc.purpose!="Manufacture");
|
||||
},
|
||||
|
||||
get_doctype_docname: function() {
|
||||
@ -339,6 +339,8 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
|
||||
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("s_warehouse", !disable_from_warehouse);
|
||||
cur_frm.fields_dict["mtn_details"].grid.set_column_disp("t_warehouse", !disable_to_warehouse);
|
||||
|
||||
cur_frm.cscript.toggle_enable_bom();
|
||||
|
||||
if(doc.purpose == 'Purchase Return') {
|
||||
doc.customer = doc.customer_name = doc.customer_address =
|
||||
doc.delivery_note_no = doc.sales_invoice_no = null;
|
||||
@ -351,6 +353,8 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
|
||||
doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
|
||||
doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['production_order'].get_query = function(doc) {
|
||||
@ -457,4 +461,5 @@ cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {
|
||||
cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) {
|
||||
return { query: "erpnext.controllers.queries.supplier_query" }
|
||||
}
|
||||
cur_frm.add_fetch('production_order', 'total_fixed_cost', 'total_fixed_cost');
|
||||
cur_frm.add_fetch('production_order', 'total_fixed_cost', 'total_fixed_cost');
|
||||
cur_frm.add_fetch('bom_no', 'total_fixed_cost', 'total_fixed_cost');
|
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@ class StockEntry(StockController):
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_uom_is_integer("stock_uom", "transfer_qty")
|
||||
self.validate_warehouse(pro_obj)
|
||||
self.validate_production_order(pro_obj)
|
||||
self.validate_production_order()
|
||||
self.get_stock_and_rate()
|
||||
self.validate_incoming_rate()
|
||||
self.validate_bom()
|
||||
@ -58,6 +58,7 @@ class StockEntry(StockController):
|
||||
self.validate_valuation_rate()
|
||||
self.set_total_amount()
|
||||
|
||||
|
||||
def on_submit(self):
|
||||
self.update_stock_ledger()
|
||||
|
||||
@ -78,7 +79,7 @@ class StockEntry(StockController):
|
||||
|
||||
def validate_purpose(self):
|
||||
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer",
|
||||
"Manufacture/Repack", "Subcontract", "Sales Return", "Purchase Return"]
|
||||
"Manufacture", "Repack", "Subcontract", "Sales Return", "Purchase Return"]
|
||||
if self.purpose not in valid_purposes:
|
||||
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
|
||||
|
||||
@ -141,7 +142,7 @@ class StockEntry(StockController):
|
||||
if self.purpose in target_mandatory and not d.t_warehouse:
|
||||
frappe.throw(_("Target warehouse is mandatory for row {0}").format(d.idx))
|
||||
|
||||
if self.purpose == "Manufacture/Repack":
|
||||
if self.purpose in ["Manufacture", "Repack"]:
|
||||
if validate_for_manufacture_repack:
|
||||
if d.bom_no:
|
||||
d.s_warehouse = None
|
||||
@ -160,14 +161,11 @@ class StockEntry(StockController):
|
||||
if cstr(d.s_warehouse) == cstr(d.t_warehouse):
|
||||
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
|
||||
|
||||
def validate_production_order(self, pro_obj=None):
|
||||
if not pro_obj:
|
||||
if self.production_order:
|
||||
pro_obj = frappe.get_doc('Production Order', self.production_order)
|
||||
else:
|
||||
return
|
||||
|
||||
if self.purpose == "Manufacture/Repack":
|
||||
def validate_production_order(self):
|
||||
if self.purpose == "Manufacture":
|
||||
# check if production order is entered
|
||||
if not self.production_order:
|
||||
frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture"))
|
||||
# check for double entry
|
||||
self.check_duplicate_entry_for_production_order()
|
||||
elif self.purpose != "Material Transfer":
|
||||
@ -196,7 +194,7 @@ class StockEntry(StockController):
|
||||
+ self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError)
|
||||
|
||||
def validate_valuation_rate(self):
|
||||
if self.purpose == "Manufacture/Repack":
|
||||
if self.purpose in ["Manufacture", "Repack"]:
|
||||
valuation_at_source, valuation_at_target = 0, 0
|
||||
for d in self.get("mtn_details"):
|
||||
if d.s_warehouse and not d.t_warehouse:
|
||||
@ -252,7 +250,7 @@ class StockEntry(StockController):
|
||||
raw_material_cost += flt(d.amount)
|
||||
|
||||
# set incoming rate for fg item
|
||||
if self.purpose == "Manufacture/Repack":
|
||||
if self.purpose in ["Manufacture", "Repack"]:
|
||||
number_of_fg_items = len([t.t_warehouse for t in self.get("mtn_details") if t.t_warehouse])
|
||||
for d in self.get("mtn_details"):
|
||||
if d.bom_no or (d.t_warehouse and number_of_fg_items == 1):
|
||||
@ -395,7 +393,7 @@ class StockEntry(StockController):
|
||||
pro_doc = frappe.get_doc("Production Order", self.production_order)
|
||||
_validate_production_order(pro_doc)
|
||||
pro_doc.run_method("update_status")
|
||||
if self.purpose == "Manufacture/Repack":
|
||||
if self.purpose == "Manufacture":
|
||||
pro_doc.run_method("update_produced_qty")
|
||||
self.update_planned_qty(pro_doc)
|
||||
|
||||
@ -467,20 +465,20 @@ class StockEntry(StockController):
|
||||
|
||||
def get_items(self):
|
||||
self.set('mtn_details', [])
|
||||
self.validate_production_order()
|
||||
|
||||
pro_obj = None
|
||||
if self.production_order:
|
||||
# common validations
|
||||
pro_obj = frappe.get_doc('Production Order', self.production_order)
|
||||
if pro_obj:
|
||||
self.validate_production_order(pro_obj)
|
||||
self.bom_no = pro_obj.bom_no
|
||||
else:
|
||||
# invalid production order
|
||||
self.production_order = None
|
||||
|
||||
if self.bom_no:
|
||||
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture/Repack",
|
||||
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
|
||||
"Subcontract"]:
|
||||
if self.production_order and self.purpose == "Material Transfer":
|
||||
item_dict = self.get_pending_raw_materials(pro_obj)
|
||||
@ -497,7 +495,7 @@ class StockEntry(StockController):
|
||||
self.add_to_stock_entry_detail(item_dict)
|
||||
|
||||
# add finished good item to Stock Entry Detail table -- along with bom_no
|
||||
if self.production_order and self.purpose == "Manufacture/Repack":
|
||||
if self.production_order and self.purpose == "Manufacture":
|
||||
item = frappe.db.get_value("Item", pro_obj.production_item, ["item_name",
|
||||
"description", "stock_uom", "expense_account", "buying_cost_center"], as_dict=1)
|
||||
self.add_to_stock_entry_detail({
|
||||
@ -513,7 +511,7 @@ class StockEntry(StockController):
|
||||
}
|
||||
}, bom_no=pro_obj.bom_no)
|
||||
|
||||
elif self.purpose in ["Material Receipt", "Manufacture/Repack"]:
|
||||
elif self.purpose in ["Material Receipt", "Repack"]:
|
||||
if self.purpose=="Material Receipt":
|
||||
self.from_warehouse = ""
|
||||
|
||||
|
@ -6,7 +6,8 @@
|
||||
"Material Issue": "icon-arrow-right",
|
||||
"Material Receipt": "icon-arrow-left",
|
||||
"Material Transfer": "icon-resize-horizontal",
|
||||
"Manufacture/Repack": "icon-wrench",
|
||||
"Manufacture": "icon-wrench",
|
||||
"Repack": "icon-wrench",
|
||||
"Sales Return": "icon-warning-sign",
|
||||
"Purchase Return": "icon-warning-sign",
|
||||
"Subcontract": "icon-truck"
|
||||
|
@ -108,6 +108,6 @@
|
||||
],
|
||||
"posting_date": "2013-01-25",
|
||||
"posting_time": "17:14:24",
|
||||
"purpose": "Manufacture/Repack"
|
||||
"purpose": "Repack"
|
||||
}
|
||||
]
|
@ -843,7 +843,7 @@ class TestStockEntry(unittest.TestCase):
|
||||
|
||||
stock_entry = frappe.new_doc("Stock Entry")
|
||||
stock_entry.update({
|
||||
"purpose": "Manufacture/Repack",
|
||||
"purpose": "Manufacture",
|
||||
"production_order": production_order.name,
|
||||
"bom_no": bom_no,
|
||||
"fg_completed_qty": "1",
|
||||
|
@ -1,224 +1,223 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-03-07 18:50:32",
|
||||
"description": "A logical Warehouse against which stock entries are made.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-03-07 18:50:32",
|
||||
"description": "A logical Warehouse against which stock entries are made.",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "warehouse_detail",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Detail",
|
||||
"oldfieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "warehouse_detail",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Detail",
|
||||
"oldfieldtype": "Section Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "warehouse_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Warehouse Name",
|
||||
"oldfieldname": "warehouse_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"fieldname": "warehouse_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Warehouse Name",
|
||||
"oldfieldname": "warehouse_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:sys_defaults.auto_accounting_for_stock",
|
||||
"description": "Account for the warehouse (Perpetual Inventory) will be created under this Account.",
|
||||
"fieldname": "create_account_under",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Parent Account",
|
||||
"options": "Account",
|
||||
"depends_on": "eval:sys_defaults.auto_accounting_for_stock",
|
||||
"description": "Account for the warehouse (Perpetual Inventory) will be created under this Account.",
|
||||
"fieldname": "create_account_under",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Parent Account",
|
||||
"options": "Account",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled",
|
||||
"fieldname": "disabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disabled",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "For Reference Only.",
|
||||
"fieldname": "warehouse_contact_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Contact Info",
|
||||
"permlevel": 0,
|
||||
"description": "For Reference Only.",
|
||||
"fieldname": "warehouse_contact_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Warehouse Contact Info",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Email Id",
|
||||
"oldfieldname": "email_id",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Email Id",
|
||||
"oldfieldname": "email_id",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "phone_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone No",
|
||||
"oldfieldname": "phone_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0,
|
||||
"fieldname": "phone_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone No",
|
||||
"oldfieldname": "phone_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "mobile_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Mobile No",
|
||||
"oldfieldname": "mobile_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0,
|
||||
"fieldname": "mobile_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Mobile No",
|
||||
"oldfieldname": "mobile_no",
|
||||
"oldfieldtype": "Int",
|
||||
"options": "Phone",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_line_1",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 1",
|
||||
"oldfieldname": "address_line_1",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_line_1",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 1",
|
||||
"oldfieldname": "address_line_1",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_line_2",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 2",
|
||||
"oldfieldname": "address_line_2",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_line_2",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 2",
|
||||
"oldfieldname": "address_line_2",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "city",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "City",
|
||||
"oldfieldname": "city",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"fieldname": "city",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "City",
|
||||
"oldfieldname": "city",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "state",
|
||||
"fieldtype": "Data",
|
||||
"label": "State",
|
||||
"oldfieldname": "state",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Suggest",
|
||||
"permlevel": 0,
|
||||
"fieldname": "state",
|
||||
"fieldtype": "Data",
|
||||
"label": "State",
|
||||
"oldfieldname": "state",
|
||||
"oldfieldtype": "Select",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "pin",
|
||||
"fieldtype": "Int",
|
||||
"label": "PIN",
|
||||
"oldfieldname": "pin",
|
||||
"oldfieldtype": "Int",
|
||||
"permlevel": 0,
|
||||
"fieldname": "pin",
|
||||
"fieldtype": "Int",
|
||||
"label": "PIN",
|
||||
"oldfieldname": "pin",
|
||||
"oldfieldtype": "Int",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-building",
|
||||
"idx": 1,
|
||||
"modified": "2014-08-04 02:55:16.750848",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Warehouse",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-building",
|
||||
"idx": 1,
|
||||
"modified": "2014-09-15 02:55:16.750848",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Warehouse",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material Master Manager",
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material Master Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material User",
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material User",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"apply_user_permissions": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "Manufacturing User"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,15 @@ def execute(filters=None):
|
||||
for wh in sorted(iwb_map[company][item]):
|
||||
qty_dict = iwb_map[company][item][wh]
|
||||
data.append([item, item_map[item]["item_name"],
|
||||
item_map[item]["item_group"],
|
||||
item_map[item]["brand"],
|
||||
item_map[item]["description"], wh,
|
||||
qty_dict.opening_qty, qty_dict.in_qty,
|
||||
qty_dict.out_qty, qty_dict.bal_qty, company
|
||||
qty_dict.uom, qty_dict.opening_qty,
|
||||
qty_dict.opening_val, qty_dict.in_qty,
|
||||
qty_dict.in_val, qty_dict.out_qty,
|
||||
qty_dict.out_val, qty_dict.bal_qty,
|
||||
qty_dict.bal_val, qty_dict.val_rate,
|
||||
company
|
||||
])
|
||||
|
||||
return columns, data
|
||||
@ -29,9 +35,11 @@ def execute(filters=None):
|
||||
def get_columns(filters):
|
||||
"""return columns based on filters"""
|
||||
|
||||
columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", \
|
||||
"Warehouse:Link/Warehouse:100", "Opening Qty:Float:90", \
|
||||
"In Qty:Float:80", "Out Qty:Float:80", "Balance Qty:Float:90", "Company:Link/Company:100"]
|
||||
columns = ["Item:Link/Item:100", "Item Name::150", "Item Group::100", "Brand::90", \
|
||||
"Description::140", "Warehouse:Link/Warehouse:100", "Stock UOM::90", "Opening Qty:Float:100", \
|
||||
"Opening Value:Float:110", "In Qty:Float:80", "In Value:Float:80", "Out Qty:Float:80", \
|
||||
"Out Value:Float:80", "Balance Qty:Float:100", "Balance Value:Float:100", \
|
||||
"Valuation Rate:Float:90", "Company:Link/Company:100"]
|
||||
|
||||
return columns
|
||||
|
||||
@ -50,8 +58,8 @@ def get_conditions(filters):
|
||||
#get all details
|
||||
def get_stock_ledger_entries(filters):
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""select item_code, warehouse,
|
||||
posting_date, actual_qty, company
|
||||
return frappe.db.sql("""select item_code, warehouse, posting_date,
|
||||
actual_qty, valuation_rate, stock_uom, company
|
||||
from `tabStock Ledger Entry`
|
||||
where docstatus < 2 %s order by item_code, warehouse""" %
|
||||
conditions, as_dict=1)
|
||||
@ -63,24 +71,37 @@ def get_item_warehouse_map(filters):
|
||||
for d in sle:
|
||||
iwb_map.setdefault(d.company, {}).setdefault(d.item_code, {}).\
|
||||
setdefault(d.warehouse, frappe._dict({\
|
||||
"opening_qty": 0.0, "in_qty": 0.0, "out_qty": 0.0, "bal_qty": 0.0
|
||||
"opening_qty": 0.0, "opening_val": 0.0,
|
||||
"in_qty": 0.0, "in_val": 0.0,
|
||||
"out_qty": 0.0, "out_val": 0.0,
|
||||
"bal_qty": 0.0, "bal_val": 0.0,
|
||||
"val_rate": 0.0, "uom": None
|
||||
}))
|
||||
qty_dict = iwb_map[d.company][d.item_code][d.warehouse]
|
||||
qty_dict.uom = d.stock_uom
|
||||
|
||||
if d.posting_date < filters["from_date"]:
|
||||
qty_dict.opening_qty += flt(d.actual_qty)
|
||||
qty_dict.opening_val += flt(d.actual_qty) * flt(d.valuation_rate)
|
||||
elif d.posting_date >= filters["from_date"] and d.posting_date <= filters["to_date"]:
|
||||
qty_dict.val_rate = d.valuation_rate
|
||||
|
||||
if flt(d.actual_qty) > 0:
|
||||
qty_dict.in_qty += flt(d.actual_qty)
|
||||
qty_dict.in_val += flt(d.actual_qty) * flt(d.valuation_rate)
|
||||
else:
|
||||
qty_dict.out_qty += abs(flt(d.actual_qty))
|
||||
qty_dict.out_val += flt(abs(flt(d.actual_qty) * flt(d.valuation_rate)))
|
||||
|
||||
qty_dict.bal_qty += flt(d.actual_qty)
|
||||
qty_dict.bal_val += flt(d.actual_qty) * flt(d.valuation_rate)
|
||||
|
||||
return iwb_map
|
||||
|
||||
def get_item_details(filters):
|
||||
item_map = {}
|
||||
for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
|
||||
for d in frappe.db.sql("select name, item_name, item_group, brand, \
|
||||
description from tabItem", as_dict=1):
|
||||
item_map.setdefault(d.name, d)
|
||||
|
||||
return item_map
|
||||
|
@ -279,7 +279,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-06-23 07:55:49.200714",
|
||||
"modified": "2014-09-26 11:37:41.026433",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Maintenance Visit",
|
||||
@ -301,7 +301,7 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "status,maintenance_type,customer,customer_name, address,mntc_date,company,fiscal_year",
|
||||
"search_fields": "status,maintenance_type,customer,customer_name,mntc_date,company,fiscal_year",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -14,9 +14,9 @@ $.extend(cur_frm.cscript, {
|
||||
erpnext.toggle_naming_series();
|
||||
if(!doc.__islocal) {
|
||||
if(cur_frm.fields_dict.status.get_status()=="Write") {
|
||||
if(doc.status!='Closed') cur_frm.add_custom_button('Close',
|
||||
if(doc.status!='Closed') cur_frm.add_custom_button(__('Close'),
|
||||
cur_frm.cscript['Close Ticket'], "icon-ok", "btn-success");
|
||||
if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket',
|
||||
if(doc.status=='Closed') cur_frm.add_custom_button(__('Re-Open Ticket'),
|
||||
cur_frm.cscript['Re-Open Ticket'], null, "btn-default");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<h2>Recurring {{ type }} Failed</h2>
|
||||
|
||||
<p>An error occured while creating recurring {{ type }} <b>{{ name }}</b> for <b>{{ customer }}</b>.</p>
|
||||
<p>An error occured while creating recurring {{ type }} <b>{{ name }}</b> for <b>{{ party }}</b>.</p>
|
||||
<p>This could be because of some invalid email ids in the {{ type }}.</p>
|
||||
<p>To stop sending repetitive error notifications from the system, we have unchecked
|
||||
"Convert into Recurring" field in the {{ type }} {{ name }}.</p>
|
||||
|
@ -1,264 +1,263 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:32",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:32",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "address_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address Details",
|
||||
"options": "icon-map-marker",
|
||||
"fieldname": "address_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address Details",
|
||||
"options": "icon-map-marker",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "Name of person or organization that this address belongs to.",
|
||||
"fieldname": "address_title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Address Title",
|
||||
"permlevel": 0,
|
||||
"description": "Name of person or organization that this address belongs to.",
|
||||
"fieldname": "address_title",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Address Title",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Address Type",
|
||||
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Address Type",
|
||||
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_line1",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 1",
|
||||
"permlevel": 0,
|
||||
"fieldname": "address_line1",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 1",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "address_line2",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 2",
|
||||
"fieldname": "address_line2",
|
||||
"fieldtype": "Data",
|
||||
"label": "Address Line 2",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "city",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "City/Town",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"fieldname": "city",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "City/Town",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "state",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "State",
|
||||
"options": "Suggest",
|
||||
"permlevel": 0,
|
||||
"fieldname": "state",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "State",
|
||||
"permlevel": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "pincode",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Pincode",
|
||||
"permlevel": 0,
|
||||
"fieldname": "pincode",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Pincode",
|
||||
"permlevel": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "country",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Country",
|
||||
"options": "Country",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"fieldname": "country",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Country",
|
||||
"options": "Country",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Email Id",
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Email Id",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "phone",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone",
|
||||
"permlevel": 0,
|
||||
"fieldname": "phone",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "fax",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"label": "Fax",
|
||||
"fieldname": "fax",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"label": "Fax",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Check to make primary address",
|
||||
"fieldname": "is_primary_address",
|
||||
"fieldtype": "Check",
|
||||
"label": "Preferred Billing Address",
|
||||
"default": "0",
|
||||
"description": "Check to make primary address",
|
||||
"fieldname": "is_primary_address",
|
||||
"fieldtype": "Check",
|
||||
"label": "Preferred Billing Address",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "Check to make Shipping Address",
|
||||
"fieldname": "is_shipping_address",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Preferred Shipping Address",
|
||||
"default": "0",
|
||||
"description": "Check to make Shipping Address",
|
||||
"fieldname": "is_shipping_address",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Preferred Shipping Address",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "linked_with",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Reference",
|
||||
"options": "icon-pushpin",
|
||||
"fieldname": "linked_with",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Reference",
|
||||
"options": "icon-pushpin",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Name",
|
||||
"permlevel": 0,
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_22",
|
||||
"fieldtype": "Column Break",
|
||||
"fieldname": "column_break_22",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "lead",
|
||||
"fieldtype": "Link",
|
||||
"label": "Lead",
|
||||
"options": "Lead",
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "lead",
|
||||
"fieldtype": "Link",
|
||||
"label": "Lead",
|
||||
"options": "Lead",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "lead_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Lead Name",
|
||||
"permlevel": 0,
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "lead_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Lead Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "icon-map-marker",
|
||||
"idx": 1,
|
||||
"in_dialog": 0,
|
||||
"modified": "2014-05-27 03:49:07.273657",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Utilities",
|
||||
"name": "Address",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-map-marker",
|
||||
"idx": 1,
|
||||
"in_dialog": 0,
|
||||
"modified": "2014-09-15 03:49:07.273657",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Utilities",
|
||||
"name": "Address",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"submit": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User",
|
||||
"submit": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance User",
|
||||
"submit": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0,
|
||||
"apply_user_permissions": 1,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "customer, supplier, sales_partner, country, state",
|
||||
"sort_field": "modified",
|
||||
],
|
||||
"search_fields": "customer, supplier, sales_partner, country, state",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
}
|
||||
|
@ -1,344 +1,342 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:32",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"creation": "2013-01-10 16:34:32",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "contact_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Contact Details",
|
||||
"options": "icon-user",
|
||||
"fieldname": "contact_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Contact Details",
|
||||
"options": "icon-user",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "first_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "First Name",
|
||||
"oldfieldname": "first_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "first_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "First Name",
|
||||
"oldfieldname": "first_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "last_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Last Name",
|
||||
"oldfieldname": "last_name",
|
||||
"oldfieldtype": "Data",
|
||||
"fieldname": "last_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Last Name",
|
||||
"oldfieldname": "last_name",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "cb00",
|
||||
"fieldtype": "Column Break",
|
||||
"fieldname": "cb00",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "Passive",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Passive\nOpen\nReplied",
|
||||
"default": "Passive",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Passive\nOpen\nReplied",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Email Id",
|
||||
"oldfieldname": "email_id",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 0,
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Email Id",
|
||||
"oldfieldname": "email_id",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "phone",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone",
|
||||
"oldfieldname": "contact_no",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"fieldname": "phone",
|
||||
"fieldtype": "Data",
|
||||
"label": "Phone",
|
||||
"oldfieldname": "contact_no",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "contact_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Reference",
|
||||
"options": "icon-pushpin",
|
||||
"fieldname": "contact_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Reference",
|
||||
"options": "icon-pushpin",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"oldfieldname": "customer",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Name",
|
||||
"permlevel": 0,
|
||||
"depends_on": "eval:!doc.supplier && !doc.sales_partner",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"oldfieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.customer && !doc.sales_partner",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"depends_on": "eval:!doc.customer && !doc.sales_partner",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"depends_on": "eval:!doc.customer && !doc.sales_partner",
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"permlevel": 0,
|
||||
"allow_on_submit": 0,
|
||||
"depends_on": "eval:!doc.customer && !doc.sales_partner",
|
||||
"fieldname": "supplier_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 0,
|
||||
"label": "Supplier Name",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:!doc.customer && !doc.supplier",
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"depends_on": "eval:!doc.customer && !doc.supplier",
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:(doc.customer || doc.supplier || doc.sales_partner)",
|
||||
"fieldname": "is_primary_contact",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Primary Contact",
|
||||
"oldfieldname": "is_primary_contact",
|
||||
"oldfieldtype": "Select",
|
||||
"default": "0",
|
||||
"depends_on": "eval:(doc.customer || doc.supplier || doc.sales_partner)",
|
||||
"fieldname": "is_primary_contact",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Primary Contact",
|
||||
"oldfieldname": "is_primary_contact",
|
||||
"oldfieldtype": "Select",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"options": "icon-file-text",
|
||||
"fieldname": "more_info",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Info",
|
||||
"options": "icon-file-text",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "mobile_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Mobile No",
|
||||
"oldfieldname": "mobile_no",
|
||||
"oldfieldtype": "Data",
|
||||
"fieldname": "mobile_no",
|
||||
"fieldtype": "Data",
|
||||
"label": "Mobile No",
|
||||
"oldfieldname": "mobile_no",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "Enter department to which this Contact belongs",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Data",
|
||||
"label": "Department",
|
||||
"options": "Suggest",
|
||||
"description": "Enter department to which this Contact belongs",
|
||||
"fieldname": "department",
|
||||
"fieldtype": "Data",
|
||||
"label": "Department",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"description": "Enter designation of this Contact",
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Data",
|
||||
"label": "Designation",
|
||||
"options": "Suggest",
|
||||
"description": "Enter designation of this Contact",
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Data",
|
||||
"label": "Designation",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "unsubscribed",
|
||||
"fieldtype": "Check",
|
||||
"label": "Unsubscribed",
|
||||
"fieldname": "unsubscribed",
|
||||
"fieldtype": "Check",
|
||||
"label": "Unsubscribed",
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"modified": "2014-09-11 18:53:17.311624",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Utilities",
|
||||
"name": "Contact",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-user",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"modified": "2014-09-11 18:53:17.311624",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Utilities",
|
||||
"name": "Contact",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Master Manager",
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Master Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance User",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Maintenance User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"match": "",
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"match": "",
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"submit": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user