Merge branch 'develop' into v13-patch-fixes-1
This commit is contained in:
commit
4bf951a85b
@ -60,4 +60,12 @@ def create_mode_of_payment(gateway, payment_type="General"):
|
||||
"default_account": payment_gateway_account
|
||||
}]
|
||||
})
|
||||
mode_of_payment.insert(ignore_permissions=True)
|
||||
mode_of_payment.insert(ignore_permissions=True)
|
||||
|
||||
def get_tracking_url(carrier, tracking_number):
|
||||
# Return the formatted Tracking URL.
|
||||
tracking_url = ''
|
||||
url_reference = frappe.get_value('Parcel Service', carrier, 'url_reference')
|
||||
if url_reference:
|
||||
tracking_url = frappe.render_template(url_reference, {'tracking_number': tracking_number})
|
||||
return tracking_url
|
||||
|
@ -118,11 +118,6 @@ class TestSalarySlip(unittest.TestCase):
|
||||
|
||||
self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 4)
|
||||
|
||||
#Gross pay calculation based on attendances
|
||||
gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
|
||||
|
||||
self.assertEqual(flt(ss.gross_pay, 2), flt(gross_pay, 2))
|
||||
|
||||
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
|
||||
|
||||
def test_salary_slip_with_holidays_included(self):
|
||||
|
@ -78,7 +78,7 @@ class Gstr1Report(object):
|
||||
place_of_supply = invoice_details.get("place_of_supply")
|
||||
ecommerce_gstin = invoice_details.get("ecommerce_gstin")
|
||||
|
||||
b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin),{
|
||||
b2cs_output.setdefault((rate, place_of_supply, ecommerce_gstin, inv),{
|
||||
"place_of_supply": "",
|
||||
"ecommerce_gstin": "",
|
||||
"rate": "",
|
||||
@ -90,7 +90,7 @@ class Gstr1Report(object):
|
||||
"invoice_value": invoice_details.get("base_grand_total"),
|
||||
})
|
||||
|
||||
row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin))
|
||||
row = b2cs_output.get((rate, place_of_supply, ecommerce_gstin, inv))
|
||||
row["place_of_supply"] = place_of_supply
|
||||
row["ecommerce_gstin"] = ecommerce_gstin
|
||||
row["rate"] = rate
|
||||
|
@ -8,7 +8,7 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Stock Transactions",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"label\": \"Delivery Note\",\n \"name\": \"Delivery Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Receipt\",\n \"name\": \"Purchase Receipt\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Pick List\",\n \"name\": \"Pick List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Delivery Trip\",\n \"name\": \"Delivery Trip\",\n \"type\": \"doctype\"\n }\n]"
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Material Request\",\n \"name\": \"Material Request\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Stock Entry\",\n \"name\": \"Stock Entry\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Customer\"\n ],\n \"label\": \"Delivery Note\",\n \"name\": \"Delivery Note\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\",\n \"Supplier\"\n ],\n \"label\": \"Purchase Receipt\",\n \"name\": \"Purchase Receipt\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"label\": \"Pick List\",\n \"name\": \"Pick List\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Shipment\",\n \"name\": \"Shipment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Delivery Trip\",\n \"name\": \"Delivery Trip\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
@ -58,7 +58,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Stock",
|
||||
"modified": "2020-10-07 18:40:17.130207",
|
||||
"modified": "2020-12-02 15:47:41.532942",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock",
|
||||
|
@ -156,6 +156,11 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
|
||||
}
|
||||
|
||||
if (!doc.is_return && doc.status!="Closed") {
|
||||
if(doc.docstatus == 1) {
|
||||
this.frm.add_custom_button(__('Shipment'), function() {
|
||||
me.make_shipment() }, __('Create'));
|
||||
}
|
||||
|
||||
if(flt(doc.per_installed, 2) < 100 && doc.docstatus==1)
|
||||
this.frm.add_custom_button(__('Installation Note'), function() {
|
||||
me.make_installation_note() }, __('Create'));
|
||||
@ -220,6 +225,13 @@ erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend(
|
||||
}
|
||||
},
|
||||
|
||||
make_shipment: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_shipment",
|
||||
frm: this.frm
|
||||
})
|
||||
},
|
||||
|
||||
make_sales_invoice: function() {
|
||||
frappe.model.open_mapped_doc({
|
||||
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
|
||||
|
@ -569,6 +569,62 @@ def make_packing_slip(source_name, target_doc=None):
|
||||
|
||||
return doclist
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_shipment(source_name, target_doc=None):
|
||||
def postprocess(source, target):
|
||||
user = frappe.db.get_value("User", frappe.session.user, ['email', 'full_name', 'phone', 'mobile_no'], as_dict=1)
|
||||
target.pickup_contact_email = user.email
|
||||
pickup_contact_display = '{}'.format(user.full_name)
|
||||
if user:
|
||||
if user.email:
|
||||
pickup_contact_display += '<br>' + user.email
|
||||
if user.phone:
|
||||
pickup_contact_display += '<br>' + user.phone
|
||||
if user.mobile_no and not user.phone:
|
||||
pickup_contact_display += '<br>' + user.mobile_no
|
||||
target.pickup_contact = pickup_contact_display
|
||||
|
||||
contact = frappe.db.get_value("Contact", source.contact_person, ['email_id', 'phone', 'mobile_no'], as_dict=1)
|
||||
delivery_contact_display = '{}'.format(source.contact_display)
|
||||
if contact:
|
||||
if contact.email_id:
|
||||
delivery_contact_display += '<br>' + contact.email_id
|
||||
if contact.phone:
|
||||
delivery_contact_display += '<br>' + contact.phone
|
||||
if contact.mobile_no and not contact.phone:
|
||||
delivery_contact_display += '<br>' + contact.mobile_no
|
||||
target.delivery_contact = delivery_contact_display
|
||||
|
||||
doclist = get_mapped_doc("Delivery Note", source_name, {
|
||||
"Delivery Note": {
|
||||
"doctype": "Shipment",
|
||||
"field_map": {
|
||||
"grand_total": "value_of_goods",
|
||||
"company": "pickup_company",
|
||||
"company_address": "pickup_address_name",
|
||||
"company_address_display": "pickup_address",
|
||||
"address_display": "delivery_address",
|
||||
"customer": "delivery_customer",
|
||||
"shipping_address_name": "delivery_address_name",
|
||||
"contact_person": "delivery_contact_name",
|
||||
"contact_email": "delivery_contact_email"
|
||||
},
|
||||
"validation": {
|
||||
"docstatus": ["=", 1]
|
||||
}
|
||||
},
|
||||
"Delivery Note Item": {
|
||||
"doctype": "Shipment Delivery Note",
|
||||
"field_map": {
|
||||
"name": "prevdoc_detail_docname",
|
||||
"parent": "prevdoc_docname",
|
||||
"parenttype": "prevdoc_doctype",
|
||||
"base_amount": "grand_total"
|
||||
}
|
||||
}
|
||||
}, target_doc, postprocess)
|
||||
|
||||
return doclist
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_return(source_name, target_doc=None):
|
||||
|
0
erpnext/stock/doctype/shipment/__init__.py
Normal file
0
erpnext/stock/doctype/shipment/__init__.py
Normal file
447
erpnext/stock/doctype/shipment/shipment.js
Normal file
447
erpnext/stock/doctype/shipment/shipment.js
Normal file
@ -0,0 +1,447 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Shipment', {
|
||||
address_query: function(frm, link_doctype, link_name, is_your_company_address) {
|
||||
return {
|
||||
query: 'frappe.contacts.doctype.address.address.address_query',
|
||||
filters: {
|
||||
link_doctype: link_doctype,
|
||||
link_name: link_name,
|
||||
is_your_company_address: is_your_company_address
|
||||
}
|
||||
};
|
||||
},
|
||||
contact_query: function(frm, link_doctype, link_name) {
|
||||
return {
|
||||
query: 'frappe.contacts.doctype.contact.contact.contact_query',
|
||||
filters: {
|
||||
link_doctype: link_doctype,
|
||||
link_name: link_name
|
||||
}
|
||||
};
|
||||
},
|
||||
onload: function(frm) {
|
||||
frm.set_query("delivery_address_name", () => {
|
||||
let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
|
||||
return frm.events.address_query(frm, frm.doc.delivery_to_type, frm.doc[delivery_to], frm.doc.delivery_to_type === 'Company' ? 1 : 0);
|
||||
});
|
||||
frm.set_query("pickup_address_name", () => {
|
||||
let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
|
||||
return frm.events.address_query(frm, frm.doc.pickup_from_type, frm.doc[pickup_from], frm.doc.pickup_from_type === 'Company' ? 1 : 0);
|
||||
});
|
||||
frm.set_query("delivery_contact_name", () => {
|
||||
let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
|
||||
return frm.events.contact_query(frm, frm.doc.delivery_to_type, frm.doc[delivery_to]);
|
||||
});
|
||||
frm.set_query("pickup_contact_name", () => {
|
||||
let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
|
||||
return frm.events.contact_query(frm, frm.doc.pickup_from_type, frm.doc[pickup_from]);
|
||||
});
|
||||
frm.set_query("delivery_note", "shipment_delivery_note", function() {
|
||||
let customer = '';
|
||||
if (frm.doc.delivery_to_type == "Customer") {
|
||||
customer = frm.doc.delivery_customer;
|
||||
}
|
||||
if (frm.doc.delivery_to_type == "Company") {
|
||||
customer = frm.doc.delivery_company;
|
||||
}
|
||||
if (customer) {
|
||||
return {
|
||||
filters: {
|
||||
customer: customer,
|
||||
docstatus: 1,
|
||||
status: ["not in", ["Cancelled"]]
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh: function() {
|
||||
$('div[data-fieldname=pickup_address] > div > .clearfix').hide();
|
||||
$('div[data-fieldname=pickup_contact] > div > .clearfix').hide();
|
||||
$('div[data-fieldname=delivery_address] > div > .clearfix').hide();
|
||||
$('div[data-fieldname=delivery_contact] > div > .clearfix').hide();
|
||||
},
|
||||
before_save: function(frm) {
|
||||
let delivery_to = `delivery_${frappe.model.scrub(frm.doc.delivery_to_type)}`;
|
||||
frm.set_value("delivery_to", frm.doc[delivery_to]);
|
||||
let pickup_from = `pickup_${frappe.model.scrub(frm.doc.pickup_from_type)}`;
|
||||
frm.set_value("pickup", frm.doc[pickup_from]);
|
||||
},
|
||||
set_pickup_company_address: function(frm) {
|
||||
frappe.db.get_value('Address', {
|
||||
address_title: frm.doc.pickup_company,
|
||||
is_your_company_address: 1
|
||||
}, 'name', (r) => {
|
||||
frm.set_value("pickup_address_name", r.name);
|
||||
});
|
||||
},
|
||||
set_delivery_company_address: function(frm) {
|
||||
frappe.db.get_value('Address', {
|
||||
address_title: frm.doc.delivery_company,
|
||||
is_your_company_address: 1
|
||||
}, 'name', (r) => {
|
||||
frm.set_value("delivery_address_name", r.name);
|
||||
});
|
||||
},
|
||||
pickup_from_type: function(frm) {
|
||||
if (frm.doc.pickup_from_type == 'Company') {
|
||||
frm.set_value("pickup_company", frappe.defaults.get_default('company'));
|
||||
frm.set_value("pickup_customer", '');
|
||||
frm.set_value("pickup_supplier", '');
|
||||
} else {
|
||||
frm.trigger('clear_pickup_fields');
|
||||
}
|
||||
if (frm.doc.pickup_from_type == 'Customer') {
|
||||
frm.set_value("pickup_company", '');
|
||||
frm.set_value("pickup_supplier", '');
|
||||
}
|
||||
if (frm.doc.pickup_from_type == 'Supplier') {
|
||||
frm.set_value("pickup_customer", '');
|
||||
frm.set_value("pickup_company", '');
|
||||
}
|
||||
},
|
||||
delivery_to_type: function(frm) {
|
||||
if (frm.doc.delivery_to_type == 'Company') {
|
||||
frm.set_value("delivery_company", frappe.defaults.get_default('company'));
|
||||
frm.set_value("delivery_customer", '');
|
||||
frm.set_value("delivery_supplier", '');
|
||||
} else {
|
||||
frm.trigger('clear_delivery_fields');
|
||||
}
|
||||
if (frm.doc.delivery_to_type == 'Customer') {
|
||||
frm.set_value("delivery_company", '');
|
||||
frm.set_value("delivery_supplier", '');
|
||||
}
|
||||
if (frm.doc.delivery_to_type == 'Supplier') {
|
||||
frm.set_value("delivery_customer", '');
|
||||
frm.set_value("delivery_company", '');
|
||||
frm.toggle_display("shipment_delivery_note", false);
|
||||
} else {
|
||||
frm.toggle_display("shipment_delivery_note", true);
|
||||
}
|
||||
},
|
||||
delivery_address_name: function(frm) {
|
||||
if (frm.doc.delivery_to_type == 'Company') {
|
||||
erpnext.utils.get_address_display(frm, 'delivery_address_name', 'delivery_address', true);
|
||||
} else {
|
||||
erpnext.utils.get_address_display(frm, 'delivery_address_name', 'delivery_address', false);
|
||||
}
|
||||
},
|
||||
pickup_address_name: function(frm) {
|
||||
if (frm.doc.pickup_from_type == 'Company') {
|
||||
erpnext.utils.get_address_display(frm, 'pickup_address_name', 'pickup_address', true);
|
||||
} else {
|
||||
erpnext.utils.get_address_display(frm, 'pickup_address_name', 'pickup_address', false);
|
||||
}
|
||||
},
|
||||
get_contact_display: function(frm, contact_name, contact_type) {
|
||||
frappe.call({
|
||||
method: "frappe.contacts.doctype.contact.contact.get_contact_details",
|
||||
args: { contact: contact_name },
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
if (!(r.message.contact_email && (r.message.contact_phone || r.message.contact_mobile))) {
|
||||
if (contact_type == 'Delivery') {
|
||||
frm.set_value('delivery_contact_name', '');
|
||||
frm.set_value('delivery_contact', '');
|
||||
} else {
|
||||
frm.set_value('pickup_contact_name', '');
|
||||
frm.set_value('pickup_contact', '');
|
||||
}
|
||||
frappe.throw(__("Email or Phone/Mobile of the Contact are mandatory to continue.") + "</br>" + __("Please set Email/Phone for the contact") + ` <a href='#Form/Contact/${contact_name}'>${contact_name}</a>`);
|
||||
}
|
||||
let contact_display = r.message.contact_display;
|
||||
if (r.message.contact_email) {
|
||||
contact_display += '<br>' + r.message.contact_email;
|
||||
}
|
||||
if (r.message.contact_phone) {
|
||||
contact_display += '<br>' + r.message.contact_phone;
|
||||
}
|
||||
if (r.message.contact_mobile && !r.message.contact_phone) {
|
||||
contact_display += '<br>' + r.message.contact_mobile;
|
||||
}
|
||||
if (contact_type == 'Delivery') {
|
||||
frm.set_value('delivery_contact', contact_display);
|
||||
if (r.message.contact_email) {
|
||||
frm.set_value('delivery_contact_email', r.message.contact_email);
|
||||
}
|
||||
} else {
|
||||
frm.set_value('pickup_contact', contact_display);
|
||||
if (r.message.contact_email) {
|
||||
frm.set_value('pickup_contact_email', r.message.contact_email);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
delivery_contact_name: function(frm) {
|
||||
if (frm.doc.delivery_contact_name) {
|
||||
frm.events.get_contact_display(frm, frm.doc.delivery_contact_name, 'Delivery');
|
||||
}
|
||||
},
|
||||
pickup_contact_name: function(frm) {
|
||||
if (frm.doc.pickup_contact_name) {
|
||||
frm.events.get_contact_display(frm, frm.doc.pickup_contact_name, 'Pickup');
|
||||
}
|
||||
},
|
||||
pickup_contact_person: function(frm) {
|
||||
if (frm.doc.pickup_contact_person) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.get_company_contact",
|
||||
args: { user: frm.doc.pickup_contact_person },
|
||||
callback: function({ message }) {
|
||||
const r = message;
|
||||
let contact_display = `${r.first_name} ${r.last_name}`;
|
||||
if (r.email) {
|
||||
contact_display += `<br>${ r.email }`;
|
||||
frm.set_value('pickup_contact_email', r.email);
|
||||
}
|
||||
if (r.phone) {
|
||||
contact_display += `<br>${ r.phone }`;
|
||||
}
|
||||
if (r.mobile_no && !r.phone) {
|
||||
contact_display += `<br>${ r.mobile_no }`;
|
||||
}
|
||||
frm.set_value('pickup_contact', contact_display);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (frm.doc.pickup_from_type === 'Company') {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.get_company_contact",
|
||||
args: { user: frappe.session.user },
|
||||
callback: function({ message }) {
|
||||
const r = message;
|
||||
let contact_display = `${r.first_name} ${r.last_name}`;
|
||||
if (r.email) {
|
||||
contact_display += `<br>${ r.email }`;
|
||||
frm.set_value('pickup_contact_email', r.email);
|
||||
}
|
||||
if (r.phone) {
|
||||
contact_display += `<br>${ r.phone }`;
|
||||
}
|
||||
if (r.mobile_no && !r.phone) {
|
||||
contact_display += `<br>${ r.mobile_no }`;
|
||||
}
|
||||
frm.set_value('pickup_contact', contact_display);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
set_company_contact: function(frm, delivery_type) {
|
||||
frappe.db.get_value('User', { name: frappe.session.user }, ['full_name', 'last_name', 'email', 'phone', 'mobile_no'], (r) => {
|
||||
if (!(r.last_name && r.email && (r.phone || r.mobile_no))) {
|
||||
if (delivery_type == 'Delivery') {
|
||||
frm.set_value('delivery_company', '');
|
||||
frm.set_value('delivery_contact', '');
|
||||
} else {
|
||||
frm.set_value('pickup_company', '');
|
||||
frm.set_value('pickup_contact', '');
|
||||
}
|
||||
frappe.throw(__("Last Name, Email or Phone/Mobile of the user are mandatory to continue.") + "</br>" + __("Please first set Last Name, Email and Phone for the user") + ` <a href="#Form/User/${frappe.session.user}">${frappe.session.user}</a>`);
|
||||
}
|
||||
let contact_display = r.full_name;
|
||||
if (r.email) {
|
||||
contact_display += '<br>' + r.email;
|
||||
}
|
||||
if (r.phone) {
|
||||
contact_display += '<br>' + r.phone;
|
||||
}
|
||||
if (r.mobile_no && !r.phone) {
|
||||
contact_display += '<br>' + r.mobile_no;
|
||||
}
|
||||
if (delivery_type == 'Delivery') {
|
||||
frm.set_value('delivery_contact', contact_display);
|
||||
if (r.email) {
|
||||
frm.set_value('delivery_contact_email', r.email);
|
||||
}
|
||||
} else {
|
||||
frm.set_value('pickup_contact', contact_display);
|
||||
if (r.email) {
|
||||
frm.set_value('pickup_contact_email', r.email);
|
||||
}
|
||||
}
|
||||
});
|
||||
frm.set_value('pickup_contact_person', frappe.session.user);
|
||||
},
|
||||
pickup_company: function(frm) {
|
||||
if (frm.doc.pickup_from_type == 'Company' && frm.doc.pickup_company) {
|
||||
frm.trigger('set_pickup_company_address');
|
||||
frm.events.set_company_contact(frm, 'Pickup');
|
||||
}
|
||||
},
|
||||
delivery_company: function(frm) {
|
||||
if (frm.doc.delivery_to_type == 'Company' && frm.doc.delivery_company) {
|
||||
frm.trigger('set_delivery_company_address');
|
||||
frm.events.set_company_contact(frm, 'Delivery');
|
||||
}
|
||||
},
|
||||
delivery_customer: function(frm) {
|
||||
frm.trigger('clear_delivery_fields');
|
||||
if (frm.doc.delivery_customer) {
|
||||
frm.events.set_address_name(frm, 'Customer', frm.doc.delivery_customer, 'Delivery');
|
||||
frm.events.set_contact_name(frm, 'Customer', frm.doc.delivery_customer, 'Delivery');
|
||||
}
|
||||
},
|
||||
delivery_supplier: function(frm) {
|
||||
frm.trigger('clear_delivery_fields');
|
||||
if (frm.doc.delivery_supplier) {
|
||||
frm.events.set_address_name(frm, 'Supplier', frm.doc.delivery_supplier, 'Delivery');
|
||||
frm.events.set_contact_name(frm, 'Supplier', frm.doc.delivery_supplier, 'Delivery');
|
||||
}
|
||||
},
|
||||
pickup_customer: function(frm) {
|
||||
if (frm.doc.pickup_customer) {
|
||||
frm.events.set_address_name(frm, 'Customer', frm.doc.pickup_customer, 'Pickup');
|
||||
frm.events.set_contact_name(frm, 'Customer', frm.doc.pickup_customer, 'Pickup');
|
||||
}
|
||||
},
|
||||
pickup_supplier: function(frm) {
|
||||
if (frm.doc.pickup_supplier) {
|
||||
frm.events.set_address_name(frm, 'Supplier', frm.doc.pickup_supplier, 'Pickup');
|
||||
frm.events.set_contact_name(frm, 'Supplier', frm.doc.pickup_supplier, 'Pickup');
|
||||
}
|
||||
},
|
||||
set_address_name: function(frm, ref_doctype, ref_docname, delivery_type) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.get_address_name",
|
||||
args: {
|
||||
ref_doctype: ref_doctype,
|
||||
docname: ref_docname
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
if (delivery_type == 'Delivery') {
|
||||
frm.set_value('delivery_address_name', r.message);
|
||||
} else {
|
||||
frm.set_value('pickup_address_name', r.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
set_contact_name: function(frm, ref_doctype, ref_docname, delivery_type) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.get_contact_name",
|
||||
args: {
|
||||
ref_doctype: ref_doctype,
|
||||
docname: ref_docname
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
if (delivery_type == 'Delivery') {
|
||||
frm.set_value('delivery_contact_name', r.message);
|
||||
} else {
|
||||
frm.set_value('pickup_contact_name', r.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
add_template: function(frm) {
|
||||
if (frm.doc.parcel_template) {
|
||||
frappe.model.with_doc("Shipment Parcel Template", frm.doc.parcel_template, () => {
|
||||
let parcel_template = frappe.model.get_doc("Shipment Parcel Template", frm.doc.parcel_template);
|
||||
let row = frappe.model.add_child(frm.doc, "Shipment Parcel", "shipment_parcel");
|
||||
row.length = parcel_template.length;
|
||||
row.width = parcel_template.width;
|
||||
row.height = parcel_template.height;
|
||||
row.weight = parcel_template.weight;
|
||||
frm.refresh_fields("shipment_parcel");
|
||||
});
|
||||
}
|
||||
},
|
||||
pickup_date: function(frm) {
|
||||
if (frm.doc.pickup_date < frappe.datetime.get_today()) {
|
||||
frappe.throw(__("Pickup Date cannot be before this day"));
|
||||
}
|
||||
if (frm.doc.pickup_date == frappe.datetime.get_today()) {
|
||||
var pickup_time = frm.events.get_pickup_time(frm);
|
||||
frm.set_value("pickup_from", pickup_time);
|
||||
frm.trigger('set_pickup_to_time');
|
||||
}
|
||||
},
|
||||
pickup_from: function(frm) {
|
||||
var pickup_time = frm.events.get_pickup_time(frm);
|
||||
if (frm.doc.pickup_from && frm.doc.pickup_date == frappe.datetime.get_today()) {
|
||||
let current_hour = pickup_time.split(':')[0];
|
||||
let current_min = pickup_time.split(':')[1];
|
||||
let pickup_hour = frm.doc.pickup_from.split(':')[0];
|
||||
let pickup_min = frm.doc.pickup_from.split(':')[1];
|
||||
if (pickup_hour < current_hour || (pickup_hour == current_hour && pickup_min < current_min)) {
|
||||
frm.set_value("pickup_from", pickup_time);
|
||||
frappe.throw(__("Pickup Time cannot be in the past"));
|
||||
}
|
||||
}
|
||||
frm.trigger('set_pickup_to_time');
|
||||
},
|
||||
get_pickup_time: function() {
|
||||
let current_hour = new Date().getHours();
|
||||
let current_min = new Date().toLocaleString('en-US', {minute: 'numeric'});
|
||||
if (current_min < 30) {
|
||||
current_min = '30';
|
||||
} else {
|
||||
current_min = '00';
|
||||
current_hour = Number(current_hour)+1;
|
||||
}
|
||||
let pickup_time = current_hour +':'+ current_min;
|
||||
return pickup_time;
|
||||
},
|
||||
set_pickup_to_time: function(frm) {
|
||||
let pickup_to_hour = Number(frm.doc.pickup_from.split(':')[0])+5;
|
||||
let pickup_to_min = frm.doc.pickup_from.split(':')[1];
|
||||
let pickup_to = pickup_to_hour +':'+ pickup_to_min;
|
||||
frm.set_value("pickup_to", pickup_to);
|
||||
},
|
||||
clear_pickup_fields: function(frm) {
|
||||
let fields = ["pickup_address_name", "pickup_contact_name", "pickup_address", "pickup_contact", "pickup_contact_email", "pickup_contact_person"];
|
||||
for (let field of fields) {
|
||||
frm.set_value(field, '');
|
||||
}
|
||||
},
|
||||
clear_delivery_fields: function(frm) {
|
||||
let fields = ["delivery_address_name", "delivery_contact_name", "delivery_address", "delivery_contact", "delivery_contact_email"];
|
||||
for (let field of fields) {
|
||||
frm.set_value(field, '');
|
||||
}
|
||||
},
|
||||
remove_email_row: function(frm, table, fieldname) {
|
||||
$.each(frm.doc[table] || [], function(i, detail) {
|
||||
if (detail.email === fieldname) {
|
||||
cur_frm.get_field(table).grid.grid_rows[i].remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Shipment Delivery Note', {
|
||||
delivery_note: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
if (row.delivery_note) {
|
||||
let row_index = row.idx - 1;
|
||||
if (validate_duplicate(frm, 'shipment_delivery_note', row.delivery_note, row_index)) {
|
||||
frappe.throw(__("You have entered a duplicate Delivery Note on Row") + ` ${row.idx}. ` + __("Please rectify and try again."));
|
||||
}
|
||||
}
|
||||
},
|
||||
grand_total: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
if (row.grand_total) {
|
||||
var value_of_goods = parseFloat(frm.doc.value_of_goods)+parseFloat(row.grand_total);
|
||||
frm.set_value("value_of_goods", Math.round(value_of_goods));
|
||||
frm.refresh_fields("value_of_goods");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var validate_duplicate = function(frm, table, fieldname, index) {
|
||||
return (
|
||||
table === 'shipment_delivery_note'
|
||||
? frm.doc[table].some((detail, i) => detail.delivery_note === fieldname && !(index === i))
|
||||
: frm.doc[table].some((detail, i) => detail.email === fieldname && !(index === i))
|
||||
);
|
||||
};
|
471
erpnext/stock/doctype/shipment/shipment.json
Normal file
471
erpnext/stock/doctype/shipment/shipment.json
Normal file
@ -0,0 +1,471 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "SHIPMENT-.#####",
|
||||
"creation": "2020-07-09 10:58:52.508703",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"heading_pickup_from",
|
||||
"pickup_from_type",
|
||||
"pickup_company",
|
||||
"pickup_customer",
|
||||
"pickup_supplier",
|
||||
"pickup",
|
||||
"pickup_address_name",
|
||||
"pickup_address",
|
||||
"pickup_contact_person",
|
||||
"pickup_contact_name",
|
||||
"pickup_contact_email",
|
||||
"pickup_contact",
|
||||
"column_break_2",
|
||||
"heading_delivery_to",
|
||||
"delivery_to_type",
|
||||
"delivery_company",
|
||||
"delivery_customer",
|
||||
"delivery_supplier",
|
||||
"delivery_to",
|
||||
"delivery_address_name",
|
||||
"delivery_address",
|
||||
"delivery_contact_name",
|
||||
"delivery_contact_email",
|
||||
"delivery_contact",
|
||||
"parcels_section",
|
||||
"shipment_parcel",
|
||||
"parcel_template",
|
||||
"add_template",
|
||||
"column_break_28",
|
||||
"shipment_delivery_note",
|
||||
"shipment_details_section",
|
||||
"pallets",
|
||||
"value_of_goods",
|
||||
"pickup_date",
|
||||
"pickup_from",
|
||||
"pickup_to",
|
||||
"column_break_36",
|
||||
"shipment_type",
|
||||
"pickup_type",
|
||||
"incoterm",
|
||||
"description_of_content",
|
||||
"section_break_40",
|
||||
"shipment_information_section",
|
||||
"service_provider",
|
||||
"shipment_id",
|
||||
"shipment_amount",
|
||||
"status",
|
||||
"tracking_url",
|
||||
"column_break_55",
|
||||
"carrier",
|
||||
"carrier_service",
|
||||
"awb_number",
|
||||
"tracking_status",
|
||||
"tracking_status_info",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "heading_pickup_from",
|
||||
"fieldtype": "Heading",
|
||||
"label": "Pickup from"
|
||||
},
|
||||
{
|
||||
"default": "Company",
|
||||
"fieldname": "pickup_from_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Pickup from",
|
||||
"options": "Company\nCustomer\nSupplier"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.pickup_from_type == 'Company'",
|
||||
"fieldname": "pickup_company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.pickup_from_type == 'Customer'",
|
||||
"fieldname": "pickup_customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.pickup_from_type == 'Supplier'",
|
||||
"fieldname": "pickup_supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier"
|
||||
},
|
||||
{
|
||||
"fieldname": "pickup",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Pickup From",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.pickup_customer || doc.pickup_supplier || doc.pickup_from_type == \"Company\"",
|
||||
"fieldname": "pickup_address_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Address",
|
||||
"options": "Address",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pickup_address",
|
||||
"fieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.pickup_customer || doc.pickup_supplier || doc.pickup_from_type !== \"Company\"",
|
||||
"fieldname": "pickup_contact_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Contact",
|
||||
"mandatory_depends_on": "eval: doc.pickup_from_type !== 'Company'",
|
||||
"options": "Contact"
|
||||
},
|
||||
{
|
||||
"fieldname": "pickup_contact_email",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Contact Email",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "pickup_contact",
|
||||
"fieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "heading_delivery_to",
|
||||
"fieldtype": "Heading",
|
||||
"label": "Delivery to"
|
||||
},
|
||||
{
|
||||
"default": "Customer",
|
||||
"fieldname": "delivery_to_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Delivery to",
|
||||
"options": "Company\nCustomer\nSupplier"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.delivery_to_type == 'Company'",
|
||||
"fieldname": "delivery_company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.delivery_to_type == 'Customer'",
|
||||
"fieldname": "delivery_customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.delivery_to_type == 'Supplier'",
|
||||
"fieldname": "delivery_supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier"
|
||||
},
|
||||
{
|
||||
"fieldname": "delivery_to",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Delivery To",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.delivery_customer || doc.delivery_supplier || doc.delivery_to_type == \"Company\"",
|
||||
"fieldname": "delivery_address_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Address",
|
||||
"options": "Address",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "delivery_address",
|
||||
"fieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval: doc.delivery_customer || doc.delivery_supplier || doc.delivery_to_type == \"Company\"",
|
||||
"fieldname": "delivery_contact_name",
|
||||
"fieldtype": "Link",
|
||||
"label": "Contact",
|
||||
"mandatory_depends_on": "eval: doc.delivery_from_type !== 'Company'",
|
||||
"options": "Contact"
|
||||
},
|
||||
{
|
||||
"fieldname": "delivery_contact_email",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Contact Email",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.delivery_contact_name",
|
||||
"fieldname": "delivery_contact",
|
||||
"fieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parcels_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Parcels"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_parcel",
|
||||
"fieldtype": "Table",
|
||||
"label": "Shipment Parcel",
|
||||
"options": "Shipment Parcel"
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Parcel Template",
|
||||
"options": "Shipment Parcel Template"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.docstatus !== 1\n",
|
||||
"fieldname": "add_template",
|
||||
"fieldtype": "Button",
|
||||
"label": "Add Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_28",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_details_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Shipment details"
|
||||
},
|
||||
{
|
||||
"default": "No",
|
||||
"fieldname": "pallets",
|
||||
"fieldtype": "Select",
|
||||
"label": "Pallets",
|
||||
"options": "No\nYes"
|
||||
},
|
||||
{
|
||||
"fieldname": "value_of_goods",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Value of Goods",
|
||||
"precision": "2",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "pickup_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Pickup Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"default": "09:00",
|
||||
"fieldname": "pickup_from",
|
||||
"fieldtype": "Time",
|
||||
"label": "Pickup from"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"default": "17:00",
|
||||
"fieldname": "pickup_to",
|
||||
"fieldtype": "Time",
|
||||
"label": "Pickup to"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_36",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Goods",
|
||||
"fieldname": "shipment_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Shipment Type",
|
||||
"options": "Goods\nDocuments"
|
||||
},
|
||||
{
|
||||
"default": "Pickup",
|
||||
"fieldname": "pickup_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Pickup Type",
|
||||
"options": "Pickup\nSelf delivery"
|
||||
},
|
||||
{
|
||||
"fieldname": "description_of_content",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Description of Content",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_40",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_information_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Shipment Information"
|
||||
},
|
||||
{
|
||||
"fieldname": "service_provider",
|
||||
"fieldtype": "Data",
|
||||
"label": "Service Provider",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Shipment ID",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Shipment Amount",
|
||||
"no_copy": 1,
|
||||
"precision": "2",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nSubmitted\nBooked\nCancelled\nCompleted",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_url",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 1,
|
||||
"label": "Tracking URL",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "carrier",
|
||||
"fieldtype": "Data",
|
||||
"label": "Carrier",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "carrier_service",
|
||||
"fieldtype": "Data",
|
||||
"label": "Carrier Service",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "awb_number",
|
||||
"fieldtype": "Data",
|
||||
"label": "AWB Number",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Tracking Status",
|
||||
"no_copy": 1,
|
||||
"options": "\nIn Progress\nDelivered\nReturned\nLost",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_status_info",
|
||||
"fieldtype": "Data",
|
||||
"label": "Tracking Status Info",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Shipment",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_55",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "incoterm",
|
||||
"fieldtype": "Select",
|
||||
"label": "Incoterm",
|
||||
"options": "EXW (Ex Works)\nFCA (Free Carrier)\nCPT (Carriage Paid To)\nCIP (Carriage and Insurance Paid to)\nDPU (Delivered At Place Unloaded)\nDAP (Delivered At Place)\nDDP (Delivered Duty Paid)"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_delivery_note",
|
||||
"fieldtype": "Table",
|
||||
"label": "Shipment Delivery Note",
|
||||
"options": "Shipment Delivery Note"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.pickup_from_type === 'Company'",
|
||||
"fieldname": "pickup_contact_person",
|
||||
"fieldtype": "Link",
|
||||
"label": "Pickup Contact Person",
|
||||
"mandatory_depends_on": "eval:doc.pickup_from_type === 'Company'",
|
||||
"options": "User"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-12-02 15:43:44.607039",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
63
erpnext/stock/doctype/shipment/shipment.py
Normal file
63
erpnext/stock/doctype/shipment/shipment.py
Normal file
@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import flt
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.party import get_party_shipping_address
|
||||
from frappe.contacts.doctype.contact.contact import get_default_contact
|
||||
|
||||
class Shipment(Document):
|
||||
def validate(self):
|
||||
self.validate_weight()
|
||||
self.set_value_of_goods()
|
||||
if self.docstatus == 0:
|
||||
self.status = 'Draft'
|
||||
|
||||
def on_submit(self):
|
||||
if not self.shipment_parcel:
|
||||
frappe.throw(_('Please enter Shipment Parcel information'))
|
||||
if self.value_of_goods == 0:
|
||||
frappe.throw(_('Value of goods cannot be 0'))
|
||||
self.status = 'Submitted'
|
||||
|
||||
def on_cancel(self):
|
||||
self.status = 'Cancelled'
|
||||
|
||||
def validate_weight(self):
|
||||
for parcel in self.shipment_parcel:
|
||||
if flt(parcel.weight) <= 0:
|
||||
frappe.throw(_('Parcel weight cannot be 0'))
|
||||
|
||||
def set_value_of_goods(self):
|
||||
value_of_goods = 0
|
||||
for entry in self.get("shipment_delivery_note"):
|
||||
value_of_goods += flt(entry.get("grand_total"))
|
||||
self.value_of_goods = value_of_goods if value_of_goods else self.value_of_goods
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_address_name(ref_doctype, docname):
|
||||
# Return address name
|
||||
return get_party_shipping_address(ref_doctype, docname)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_contact_name(ref_doctype, docname):
|
||||
# Return address name
|
||||
return get_default_contact(ref_doctype, docname)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_company_contact(user):
|
||||
contact = frappe.db.get_value('User', user, [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'phone',
|
||||
'mobile_no',
|
||||
'gender',
|
||||
], as_dict=1)
|
||||
if not contact.phone:
|
||||
contact.phone = contact.mobile_no
|
||||
return contact
|
8
erpnext/stock/doctype/shipment/shipment_list.js
Normal file
8
erpnext/stock/doctype/shipment/shipment_list.js
Normal file
@ -0,0 +1,8 @@
|
||||
frappe.listview_settings['Shipment'] = {
|
||||
add_fields: ["status"],
|
||||
get_indicator: function(doc) {
|
||||
if (doc.status=='Booked') {
|
||||
return [__("Booked"), "green"];
|
||||
}
|
||||
}
|
||||
};
|
240
erpnext/stock/doctype/shipment/test_shipment.py
Normal file
240
erpnext/stock/doctype/shipment/test_shipment.py
Normal file
@ -0,0 +1,240 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
from datetime import date, timedelta
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.stock.doctype.delivery_note.delivery_note import make_shipment
|
||||
|
||||
class TestShipment(unittest.TestCase):
|
||||
def test_shipment_from_delivery_note(self):
|
||||
delivery_note = create_test_delivery_note()
|
||||
delivery_note.submit()
|
||||
shipment = create_test_shipment([ delivery_note ])
|
||||
shipment.submit()
|
||||
second_shipment = make_shipment(delivery_note.name)
|
||||
self.assertEqual(second_shipment.value_of_goods, delivery_note.grand_total)
|
||||
self.assertEqual(len(second_shipment.shipment_delivery_note), 1)
|
||||
self.assertEqual(second_shipment.shipment_delivery_note[0].delivery_note, delivery_note.name)
|
||||
|
||||
def create_test_delivery_note():
|
||||
company = get_shipment_company()
|
||||
customer = get_shipment_customer()
|
||||
item = get_shipment_item(company.name)
|
||||
posting_date = date.today() + timedelta(days=1)
|
||||
|
||||
create_material_receipt(item, company.name)
|
||||
delivery_note = frappe.new_doc("Delivery Note")
|
||||
delivery_note.company = company.name
|
||||
delivery_note.posting_date = posting_date.strftime("%Y-%m-%d")
|
||||
delivery_note.posting_time = '10:00'
|
||||
delivery_note.customer = customer.name
|
||||
delivery_note.append('items',
|
||||
{
|
||||
"item_code": item.name,
|
||||
"item_name": item.item_name,
|
||||
"description": 'Test delivery note for shipment',
|
||||
"qty": 5,
|
||||
"uom": 'Nos',
|
||||
"warehouse": 'Stores - SC',
|
||||
"rate": item.standard_rate,
|
||||
"cost_center": 'Main - SC'
|
||||
}
|
||||
)
|
||||
delivery_note.insert()
|
||||
frappe.db.commit()
|
||||
return delivery_note
|
||||
|
||||
|
||||
def create_test_shipment(delivery_notes = None):
|
||||
company = get_shipment_company()
|
||||
company_address = get_shipment_company_address(company.name)
|
||||
customer = get_shipment_customer()
|
||||
customer_address = get_shipment_customer_address(customer.name)
|
||||
customer_contact = get_shipment_customer_contact(customer.name)
|
||||
posting_date = date.today() + timedelta(days=5)
|
||||
|
||||
shipment = frappe.new_doc("Shipment")
|
||||
shipment.pickup_from_type = 'Company'
|
||||
shipment.pickup_company = company.name
|
||||
shipment.pickup_address_name = company_address.name
|
||||
shipment.delivery_to_type = 'Customer'
|
||||
shipment.delivery_customer = customer.name
|
||||
shipment.delivery_address_name = customer_address.name
|
||||
shipment.delivery_contact_name = customer_contact.name
|
||||
shipment.pallets = 'No'
|
||||
shipment.shipment_type = 'Goods'
|
||||
shipment.value_of_goods = 1000
|
||||
shipment.pickup_type = 'Pickup'
|
||||
shipment.pickup_date = posting_date.strftime("%Y-%m-%d")
|
||||
shipment.pickup_from = '09:00'
|
||||
shipment.pickup_to = '17:00'
|
||||
shipment.description_of_content = 'unit test entry'
|
||||
for delivery_note in delivery_notes:
|
||||
shipment.append('shipment_delivery_note',
|
||||
{
|
||||
"delivery_note": delivery_note.name
|
||||
}
|
||||
)
|
||||
shipment.append('shipment_parcel',
|
||||
{
|
||||
"length": 5,
|
||||
"width": 5,
|
||||
"height": 5,
|
||||
"weight": 5,
|
||||
"count": 5
|
||||
}
|
||||
)
|
||||
shipment.insert()
|
||||
frappe.db.commit()
|
||||
return shipment
|
||||
|
||||
|
||||
def get_shipment_customer_contact(customer_name):
|
||||
contact_fname = 'Customer Shipment'
|
||||
contact_lname = 'Testing'
|
||||
customer_name = contact_fname + ' ' + contact_lname
|
||||
contacts = frappe.get_all("Contact", fields=["name"], filters = {"name": customer_name})
|
||||
if len(contacts):
|
||||
return contacts[0]
|
||||
else:
|
||||
return create_customer_contact(contact_fname, contact_lname)
|
||||
|
||||
|
||||
def get_shipment_customer_address(customer_name):
|
||||
address_title = customer_name + ' address 123'
|
||||
customer_address = frappe.get_all("Address", fields=["name"], filters = {"address_title": address_title})
|
||||
if len(customer_address):
|
||||
return customer_address[0]
|
||||
else:
|
||||
return create_shipment_address(address_title, customer_name, 81929)
|
||||
|
||||
def get_shipment_customer():
|
||||
customer_name = 'Shipment Customer'
|
||||
customer = frappe.get_all("Customer", fields=["name"], filters = {"name": customer_name})
|
||||
if len(customer):
|
||||
return customer[0]
|
||||
else:
|
||||
return create_shipment_customer(customer_name)
|
||||
|
||||
def get_shipment_company_address(company_name):
|
||||
address_title = company_name + ' address 123'
|
||||
addresses = frappe.get_all("Address", fields=["name"], filters = {"address_title": address_title})
|
||||
if len(addresses):
|
||||
return addresses[0]
|
||||
else:
|
||||
return create_shipment_address(address_title, company_name, 80331)
|
||||
|
||||
def get_shipment_company():
|
||||
company_name = 'Shipment Company'
|
||||
abbr = 'SC'
|
||||
companies = frappe.get_all("Company", fields=["name"], filters = {"company_name": company_name})
|
||||
if len(companies):
|
||||
return companies[0]
|
||||
else:
|
||||
return create_shipment_company(company_name, abbr)
|
||||
|
||||
def get_shipment_item(company_name):
|
||||
item_name = 'Testing Shipment item'
|
||||
items = frappe.get_all("Item",
|
||||
fields=["name", "item_name", "item_code", "standard_rate"],
|
||||
filters = {"item_name": item_name}
|
||||
)
|
||||
if len(items):
|
||||
return items[0]
|
||||
else:
|
||||
return create_shipment_item(item_name, company_name)
|
||||
|
||||
def create_shipment_address(address_title, company_name, postal_code):
|
||||
address = frappe.new_doc("Address")
|
||||
address.address_title = address_title
|
||||
address.address_type = 'Shipping'
|
||||
address.address_line1 = company_name + ' address line 1'
|
||||
address.city = 'Random City'
|
||||
address.postal_code = postal_code
|
||||
address.country = 'Germany'
|
||||
address.insert()
|
||||
return address
|
||||
|
||||
|
||||
def create_customer_contact(fname, lname):
|
||||
customer = frappe.new_doc("Contact")
|
||||
customer.customer_name = fname + ' ' + lname
|
||||
customer.first_name = fname
|
||||
customer.last_name = lname
|
||||
customer.is_primary_contact = 1
|
||||
customer.is_billing_contact = 1
|
||||
customer.append('email_ids',
|
||||
{
|
||||
'email_id': 'randomme@email.com',
|
||||
'is_primary': 1
|
||||
}
|
||||
)
|
||||
customer.append('phone_nos',
|
||||
{
|
||||
'phone': '123123123',
|
||||
'is_primary_phone': 1,
|
||||
'is_primary_mobile_no': 1
|
||||
}
|
||||
)
|
||||
customer.status = 'Passive'
|
||||
customer.insert()
|
||||
return customer
|
||||
|
||||
|
||||
def create_shipment_company(company_name, abbr):
|
||||
company = frappe.new_doc("Company")
|
||||
company.company_name = company_name
|
||||
company.abbr = abbr
|
||||
company.default_currency = 'EUR'
|
||||
company.country = 'Germany'
|
||||
company.insert()
|
||||
return company
|
||||
|
||||
def create_shipment_customer(customer_name):
|
||||
customer = frappe.new_doc("Customer")
|
||||
customer.customer_name = customer_name
|
||||
customer.customer_type = 'Company'
|
||||
customer.customer_group = 'All Customer Groups'
|
||||
customer.territory = 'All Territories'
|
||||
customer.gst_category = 'Unregistered'
|
||||
customer.insert()
|
||||
return customer
|
||||
|
||||
def create_material_receipt(item, company):
|
||||
posting_date = date.today()
|
||||
stock = frappe.new_doc("Stock Entry")
|
||||
stock.company = company
|
||||
stock.stock_entry_type = 'Material Receipt'
|
||||
stock.posting_date = posting_date.strftime("%Y-%m-%d")
|
||||
stock.append('items',
|
||||
{
|
||||
"t_warehouse": 'Stores - SC',
|
||||
"item_code": item.name,
|
||||
"qty": 5,
|
||||
"uom": 'Nos',
|
||||
"basic_rate": item.standard_rate,
|
||||
"cost_center": 'Main - SC'
|
||||
}
|
||||
)
|
||||
stock.insert()
|
||||
stock.submit()
|
||||
|
||||
|
||||
def create_shipment_item(item_name, company_name):
|
||||
item = frappe.new_doc("Item")
|
||||
item.item_name = item_name
|
||||
item.item_code = item_name
|
||||
item.item_group = 'All Item Groups'
|
||||
item.stock_uom = 'Nos'
|
||||
item.standard_rate = 50
|
||||
item.append('item_defaults',
|
||||
{
|
||||
"company": company_name,
|
||||
"default_warehouse": 'Stores - SC'
|
||||
}
|
||||
)
|
||||
item.insert()
|
||||
return item
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-07-09 11:52:57.939021",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"delivery_note",
|
||||
"grand_total"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "delivery_note",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Delivery Note",
|
||||
"options": "Delivery Note",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "grand_total",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Value",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-12-02 15:44:34.028703",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment Delivery Note",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ShipmentDeliveryNote(Document):
|
||||
pass
|
0
erpnext/stock/doctype/shipment_parcel/__init__.py
Normal file
0
erpnext/stock/doctype/shipment_parcel/__init__.py
Normal file
65
erpnext/stock/doctype/shipment_parcel/shipment_parcel.json
Normal file
65
erpnext/stock/doctype/shipment_parcel/shipment_parcel.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-07-09 11:28:48.887737",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"length",
|
||||
"width",
|
||||
"height",
|
||||
"weight",
|
||||
"count"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "length",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Length (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "width",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Width (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "height",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Height (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "weight",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Weight (kg)",
|
||||
"precision": "1",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "count",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Count",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-07-09 12:54:14.847170",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment Parcel",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
10
erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
Normal file
10
erpnext/stock/doctype/shipment_parcel/shipment_parcel.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ShipmentParcel(Document):
|
||||
pass
|
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Shipment Parcel Template', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -0,0 +1,78 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:parcel_template_name",
|
||||
"creation": "2020-07-09 11:43:43.470339",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parcel_template_name",
|
||||
"length",
|
||||
"width",
|
||||
"height",
|
||||
"weight"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "length",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Length (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "width",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Width (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "height",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Height (cm)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "weight",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Weight (kg)",
|
||||
"precision": "1",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_template_name",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Parcel Template Name",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-09-28 12:51:00.320421",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment Parcel Template",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ShipmentParcelTemplate(Document):
|
||||
pass
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestShipmentParcelTemplate(unittest.TestCase):
|
||||
pass
|
@ -164,7 +164,7 @@ def get_stock_ledger_entries(filters, items):
|
||||
select
|
||||
sle.item_code, warehouse, sle.posting_date, sle.actual_qty, sle.valuation_rate,
|
||||
sle.company, sle.voucher_type, sle.qty_after_transaction, sle.stock_value_difference,
|
||||
sle.item_code as name, sle.voucher_no
|
||||
sle.item_code as name, sle.voucher_no, sle.stock_value
|
||||
from
|
||||
`tabStock Ledger Entry` sle force index (posting_sort_index)
|
||||
where sle.docstatus < 2 %s %s
|
||||
@ -197,7 +197,7 @@ def get_item_warehouse_map(filters, sle):
|
||||
else:
|
||||
qty_diff = flt(d.actual_qty)
|
||||
|
||||
value_diff = flt(d.stock_value_difference)
|
||||
value_diff = flt(d.stock_value) - flt(qty_dict.bal_val)
|
||||
|
||||
if d.posting_date < from_date:
|
||||
qty_dict.opening_qty += qty_diff
|
||||
|
Loading…
Reference in New Issue
Block a user