Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
605cc93c90 | ||
|
|
1644fce273 | ||
|
|
8cc2bf7fcf | ||
|
|
fe6409debf | ||
|
|
edc58619d1 | ||
|
|
85800fa929 | ||
|
|
60ec0128a2 | ||
|
|
90e0700e24 | ||
|
|
48156e3d8b | ||
|
|
8b353e5e15 | ||
|
|
fcbd4d7638 | ||
|
|
9409efe02a | ||
|
|
b645a217fd | ||
|
|
ef295d2977 | ||
|
|
2d0e31b479 | ||
|
|
2678ed181a | ||
|
|
1fce0b1f79 | ||
|
|
649660d9f0 | ||
|
|
797e0713ea | ||
|
|
6a0ffabbd0 | ||
|
|
56f58cfa68 | ||
|
|
677ef0c3cf | ||
|
|
64367a905a | ||
|
|
c565de2c12 | ||
|
|
908f2dc0fd | ||
|
|
0b1a8e13fd |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app_name": "ERPNext",
|
||||
"app_version": "3.3.0",
|
||||
"app_version": "3.3.3",
|
||||
"base_template": "app/portal/templates/base.html",
|
||||
"modules": {
|
||||
"Accounts": {
|
||||
@@ -74,5 +74,5 @@
|
||||
"type": "module"
|
||||
}
|
||||
},
|
||||
"requires_framework_version": "==3.3.0"
|
||||
"requires_framework_version": "==3.3.1"
|
||||
}
|
||||
@@ -1,28 +1,56 @@
|
||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if (!doc.status) doc.status = 'Draft';
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
}
|
||||
$.extend(cur_frm.cscript, {
|
||||
onload: function (doc, dt, dn) {
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
cur_frm.dashboard.reset();
|
||||
erpnext.hide_naming_series();
|
||||
cur_frm.set_intro("");
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
if (!doc.status) doc.status = 'Draft';
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
|
||||
if(doc.docstatus===0 && !doc.__islocal) {
|
||||
cur_frm.set_intro(wn._("Submit this Production Order for further processing."));
|
||||
} else if(doc.docstatus===1) {
|
||||
var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
|
||||
cur_frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
|
||||
this.frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
|
||||
},
|
||||
|
||||
if(doc.status === "Stopped") {
|
||||
cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
|
||||
refresh: function(doc, dt, dn) {
|
||||
this.frm.dashboard.reset();
|
||||
erpnext.hide_naming_series();
|
||||
this.frm.set_intro("");
|
||||
cfn_set_fields(doc, dt, dn);
|
||||
|
||||
if (doc.docstatus === 0 && !doc.__islocal) {
|
||||
this.frm.set_intro(wn._("Submit this Production Order for further processing."));
|
||||
} else if (doc.docstatus === 1) {
|
||||
var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
|
||||
this.frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
|
||||
|
||||
if(doc.status === "Stopped") {
|
||||
this.frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
production_item: function(doc) {
|
||||
return this.frm.call({
|
||||
method: "get_item_details",
|
||||
args: { item: doc.production_item }
|
||||
});
|
||||
},
|
||||
|
||||
make_se: function(purpose) {
|
||||
var me = this;
|
||||
|
||||
wn.call({
|
||||
method:"manufacturing.doctype.production_order.production_order.make_stock_entry",
|
||||
args: {
|
||||
"production_order_id": me.frm.doc.name,
|
||||
"purpose": purpose
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = wn.model.sync(r.message);
|
||||
wn.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var cfn_set_fields = function(doc, dt, dn) {
|
||||
if (doc.docstatus == 1) {
|
||||
@@ -38,13 +66,6 @@ var cfn_set_fields = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.production_item = function(doc) {
|
||||
return cur_frm.call({
|
||||
method: "get_item_details",
|
||||
args: { item: doc.production_item }
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Stop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(wn._("Do you really want to stop production order: " + doc.name));
|
||||
@@ -57,7 +78,7 @@ cur_frm.cscript['Unstop Production Order'] = function() {
|
||||
var doc = cur_frm.doc;
|
||||
var check = confirm(wn._("Do really want to unstop production order: " + doc.name));
|
||||
if (check)
|
||||
return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
|
||||
}
|
||||
|
||||
cur_frm.cscript['Transfer Raw Materials'] = function() {
|
||||
@@ -68,20 +89,6 @@ cur_frm.cscript['Update Finished Goods'] = function() {
|
||||
cur_frm.cscript.make_se('Manufacture/Repack');
|
||||
}
|
||||
|
||||
cur_frm.cscript.make_se = function(purpose) {
|
||||
wn.call({
|
||||
method:"manufacturing.doctype.production_order.production_order.make_stock_entry",
|
||||
args: {
|
||||
"production_order_id": cur_frm.doc.name,
|
||||
"purpose": purpose
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = wn.model.sync(r.message);
|
||||
wn.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['production_item'].get_query = function(doc) {
|
||||
return {
|
||||
filters:[
|
||||
@@ -98,7 +105,6 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.set_query("bom_no", function(doc) {
|
||||
if (doc.production_item) {
|
||||
return{
|
||||
|
||||
@@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt, nowdate
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint, _
|
||||
|
||||
|
||||
class OverProductionError(webnotes.ValidationError): pass
|
||||
|
||||
class DocType:
|
||||
@@ -37,15 +36,20 @@ class DocType:
|
||||
and is_active=1 and item=%s"""
|
||||
, (self.doc.bom_no, self.doc.production_item), as_dict =1)
|
||||
if not bom:
|
||||
msgprint("""Incorrect BOM: %s entered.
|
||||
webnotes.throw("""Incorrect BOM: %s entered.
|
||||
May be BOM not exists or inactive or not submitted
|
||||
or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1)
|
||||
or for some other item.""" % cstr(self.doc.bom_no))
|
||||
|
||||
def validate_sales_order(self):
|
||||
if self.doc.sales_order:
|
||||
if not webnotes.conn.sql("""select name from `tabSales Order`
|
||||
where name=%s and docstatus = 1""", self.doc.sales_order):
|
||||
msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1)
|
||||
so = webnotes.conn.sql("""select name, delivery_date from `tabSales Order`
|
||||
where name=%s and docstatus = 1""", self.doc.sales_order, as_dict=1)[0]
|
||||
|
||||
if not so.name:
|
||||
webnotes.throw("Sales Order: %s is not valid" % self.doc.sales_order)
|
||||
|
||||
if not self.doc.expected_delivery_date:
|
||||
self.doc.expected_delivery_date = so.delivery_date
|
||||
|
||||
self.validate_production_order_against_so()
|
||||
|
||||
@@ -76,11 +80,11 @@ class DocType:
|
||||
so_qty = flt(so_item_qty) + flt(dnpi_qty)
|
||||
|
||||
if total_qty > so_qty:
|
||||
webnotes.msgprint(_("Total production order qty for item") + ": " +
|
||||
webnotes.throw(_("Total production order qty for item") + ": " +
|
||||
cstr(self.doc.production_item) + _(" against sales order") + ": " +
|
||||
cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
|
||||
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
|
||||
_("Please reduce qty."), raise_exception=OverProductionError)
|
||||
_("Please reduce qty."), exc=OverProductionError)
|
||||
|
||||
def stop_unstop(self, status):
|
||||
""" Called from client side on Stop/Unstop event"""
|
||||
@@ -114,8 +118,8 @@ class DocType:
|
||||
stock_entry = webnotes.conn.sql("""select name from `tabStock Entry`
|
||||
where production_order = %s and docstatus = 1""", self.doc.name)
|
||||
if stock_entry:
|
||||
msgprint("""Submitted Stock Entry %s exists against this production order.
|
||||
Hence can not be cancelled.""" % stock_entry[0][0], raise_exception=1)
|
||||
webnotes.throw("""Submitted Stock Entry %s exists against this production order.
|
||||
Hence can not be cancelled.""" % stock_entry[0][0])
|
||||
|
||||
webnotes.conn.set(self.doc,'status', 'Cancelled')
|
||||
self.update_planned_qty(-self.doc.qty)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-01-10 16:34:16",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-02 14:05:44",
|
||||
"modified": "2013-12-18 13:22:14",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -136,6 +136,14 @@
|
||||
"oldfieldtype": "Currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "sales_order",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "expected_delivery_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Expected Delivery Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "warehouses",
|
||||
|
||||
@@ -186,7 +186,6 @@ class DocType:
|
||||
else :
|
||||
msgprint(_("No Production Order created."))
|
||||
|
||||
|
||||
def get_distinct_items_and_boms(self):
|
||||
""" Club similar BOM and item for processing
|
||||
bom_dict {
|
||||
|
||||
@@ -5,19 +5,28 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.reload_doc("setup", "doctype", "email_digest")
|
||||
|
||||
from webnotes.profile import get_system_managers
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
if not system_managers:
|
||||
return
|
||||
|
||||
# no default company
|
||||
company = webnotes.conn.sql_list("select name from `tabCompany`")
|
||||
if company:
|
||||
company = company[0]
|
||||
if not company:
|
||||
return
|
||||
|
||||
# scheduler errors digest
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": webnotes.conn.get_default("company"),
|
||||
"company": company,
|
||||
"frequency": "Daily",
|
||||
"enabled": 1,
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1
|
||||
})
|
||||
edigest.insert()
|
||||
edigest.insert()
|
||||
|
||||
@@ -261,4 +261,5 @@ patch_list = [
|
||||
"execute:webnotes.delete_doc('Report', 'Payment Made With Ageing')",
|
||||
"patches.1311.p07_scheduler_errors_digest",
|
||||
"patches.1311.p08_email_digest_recipients",
|
||||
"execute:webnotes.delete_doc('DocType', 'Warehouse Type')",
|
||||
]
|
||||
@@ -16,8 +16,6 @@ import webnotes
|
||||
from webnotes.utils import get_request_site_address, cstr
|
||||
from webnotes import _
|
||||
|
||||
from backup_manager import ignore_list
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_dropbox_authorize_url():
|
||||
sess = get_dropbox_session()
|
||||
@@ -100,9 +98,7 @@ def backup_to_dropbox():
|
||||
path = get_files_path()
|
||||
for filename in os.listdir(path):
|
||||
filename = cstr(filename)
|
||||
if filename in ignore_list:
|
||||
continue
|
||||
|
||||
|
||||
found = False
|
||||
filepath = os.path.join(path, filename)
|
||||
for file_metadata in response["contents"]:
|
||||
|
||||
@@ -87,7 +87,7 @@ $.extend(cur_frm.cscript, {
|
||||
cur_frm.save();
|
||||
},
|
||||
|
||||
upload_backups_to_gdrive: function() {
|
||||
cur_frm.save();
|
||||
},
|
||||
// upload_backups_to_gdrive: function() {
|
||||
// cur_frm.save();
|
||||
// },
|
||||
});
|
||||
@@ -7,8 +7,6 @@ from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import _
|
||||
|
||||
ignore_list = []
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
@@ -39,10 +37,6 @@ def take_backups_dropbox():
|
||||
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
|
||||
error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
|
||||
webnotes.errprint(error_message)
|
||||
|
||||
if not webnotes.conn:
|
||||
webnotes.connect()
|
||||
|
||||
send_email(False, "Dropbox", error_message)
|
||||
|
||||
#backup to gdrive
|
||||
@@ -62,6 +56,7 @@ def take_backups_gdrive():
|
||||
send_email(False, "Google Drive", error_message)
|
||||
|
||||
def send_email(success, service_name, error_status=None):
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
if success:
|
||||
subject = "Backup Upload Successful"
|
||||
message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you
|
||||
@@ -76,7 +71,8 @@ def send_email(success, service_name, error_status=None):
|
||||
<p>Please contact your system manager for more information.</p>
|
||||
""" % (service_name, error_status)
|
||||
|
||||
# email system managers
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","),
|
||||
subject=subject, msg=message)
|
||||
if not webnotes.conn:
|
||||
webnotes.connect()
|
||||
|
||||
recipients = webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(",")
|
||||
sendmail(recipients, subject=subject, msg=message)
|
||||
|
||||
@@ -158,6 +158,10 @@ def set_defaults(args):
|
||||
hr_settings.doc.emp_created_by = "Naming Series"
|
||||
hr_settings.save()
|
||||
|
||||
email_settings = webnotes.bean("Email Settings")
|
||||
email_settings.doc.send_print_in_body_and_attachment = 1
|
||||
email_settings.save()
|
||||
|
||||
# control panel
|
||||
cp = webnotes.doc("Control Panel", "Control Panel")
|
||||
cp.company_name = args["company_name"]
|
||||
@@ -175,7 +179,8 @@ def create_email_digest():
|
||||
if not system_managers:
|
||||
return
|
||||
|
||||
for company in webnotes.conn.sql_list("select name FROM `tabCompany`"):
|
||||
companies = webnotes.conn.sql_list("select name FROM `tabCompany`")
|
||||
for company in companies:
|
||||
if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company):
|
||||
edigest = webnotes.bean({
|
||||
"doctype": "Email Digest",
|
||||
@@ -192,16 +197,17 @@ def create_email_digest():
|
||||
edigest.insert()
|
||||
|
||||
# scheduler errors digest
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": webnotes.conn.get_default("company"),
|
||||
"frequency": "Daily",
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1,
|
||||
"enabled": 1
|
||||
})
|
||||
edigest.insert()
|
||||
if companies:
|
||||
edigest = webnotes.new_bean("Email Digest")
|
||||
edigest.doc.fields.update({
|
||||
"name": "Scheduler Errors",
|
||||
"company": companies[0],
|
||||
"frequency": "Daily",
|
||||
"recipient_list": "\n".join(system_managers),
|
||||
"scheduler_errors": 1,
|
||||
"enabled": 1
|
||||
})
|
||||
edigest.insert()
|
||||
|
||||
def get_fy_details(fy_start_date, fy_end_date):
|
||||
start_year = getdate(fy_start_date).year
|
||||
|
||||
@@ -123,14 +123,14 @@ class DocType(DocListController, WebsiteGenerator):
|
||||
msgprint("'Has Serial No' can not be 'Yes' for non-stock item", raise_exception=1)
|
||||
|
||||
def check_for_active_boms(self):
|
||||
if self.doc.is_active != "Yes" or self.doc.is_purchase_item != "Yes":
|
||||
if self.doc.is_purchase_item != "Yes":
|
||||
bom_mat = webnotes.conn.sql("""select distinct t1.parent
|
||||
from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
|
||||
and t1.item_code =%s and ifnull(t1.bom_no, '') = '' and t2.is_active = 1
|
||||
and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
|
||||
|
||||
if bom_mat and bom_mat[0][0]:
|
||||
webnotes.throw(_("Item must be active and purchase item, \
|
||||
webnotes.throw(_("Item must be a purchase item, \
|
||||
as it is present in one or many Active BOMs"))
|
||||
|
||||
if self.doc.is_manufactured_item != "Yes":
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-02-22 01:28:02",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-03 20:36:45",
|
||||
"modified": "2013-12-18 14:52:02",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -219,7 +219,7 @@
|
||||
"fieldname": "sales_order_no",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Order No",
|
||||
"no_copy": 1,
|
||||
"no_copy": 0,
|
||||
"options": "Sales Order",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-05-24 19:29:10",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-11-02 19:41:45",
|
||||
"modified": "2013-12-18 10:38:39",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@@ -326,7 +326,7 @@
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Required By",
|
||||
"no_copy": 1,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "schedule_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 1,
|
||||
|
||||
@@ -26,10 +26,10 @@ def execute(filters=None):
|
||||
|
||||
def get_columns():
|
||||
return ["Item Code:Link/Item:140", "Item Name::100", "Description::200",
|
||||
"Brand:Link/Brand:100", "Warehouse:Link/Warehouse:120", "UOM:Link/UOM:100",
|
||||
"Actual Qty:Float:100", "Planned Qty:Float:100", "Requested Qty:Float:110",
|
||||
"Ordered Qty:Float:100", "Reserved Qty:Float:100", "Projected Qty:Float:100",
|
||||
"Reorder Level:Float:100", "Reorder Qty:Float:100"]
|
||||
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100", "Warehouse:Link/Warehouse:120",
|
||||
"UOM:Link/UOM:100", "Actual Qty:Float:100", "Planned Qty:Float:100",
|
||||
"Requested Qty:Float:110", "Ordered Qty:Float:100", "Reserved Qty:Float:100",
|
||||
"Projected Qty:Float:100", "Reorder Level:Float:100", "Reorder Qty:Float:100"]
|
||||
|
||||
def get_item_conditions(filters):
|
||||
conditions = []
|
||||
|
||||
Reference in New Issue
Block a user