Provision to edit customer and address details
This commit is contained in:
parent
adcb3c62fa
commit
1312fe31a9
@ -26,13 +26,15 @@ def get_pos_data():
|
||||
update_multi_mode_option(doc, pos_profile)
|
||||
default_print_format = pos_profile.get('print_format') or "Point of Sale"
|
||||
print_template = frappe.db.get_value('Print Format', default_print_format, 'html')
|
||||
customers = get_customers_list(pos_profile)
|
||||
|
||||
return {
|
||||
'doc': doc,
|
||||
'default_customer': pos_profile.get('customer'),
|
||||
'items': get_items_list(pos_profile),
|
||||
'item_groups': get_item_group(pos_profile),
|
||||
'customers': get_customers_list(pos_profile),
|
||||
'customers': customers,
|
||||
'address': get_customers_address(customers),
|
||||
'serial_no_data': get_serial_no_data(pos_profile, doc.company),
|
||||
'batch_no_data': get_batch_no_data(),
|
||||
'tax_data': get_item_tax_data(),
|
||||
@ -164,6 +166,19 @@ def get_customers_list(pos_profile):
|
||||
territory from tabCustomer where disabled = 0
|
||||
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
|
||||
|
||||
def get_customers_address(customers):
|
||||
customer_address = {}
|
||||
for data in customers:
|
||||
address = frappe.db.sql(""" select name, address_line1, address_line2, city, state,
|
||||
email_id, phone, fax, pincode from `tabAddress` where is_primary_address =1 and name in
|
||||
(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
|
||||
and parenttype = 'Address')""", data.name, as_dict=1)
|
||||
if address:
|
||||
address_data = address[0]
|
||||
address_data.update({'full_name': data.customer_name})
|
||||
customer_address[data.name] = address_data
|
||||
return customer_address
|
||||
|
||||
def get_child_nodes(group_type, root):
|
||||
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
|
||||
return frappe.db.sql_list(""" Select name from `tab{tab}` where
|
||||
@ -258,13 +273,17 @@ def get_pricing_rule_data(doc):
|
||||
return pricing_rules
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_invoice(doc_list, email_queue_list):
|
||||
def make_invoice(doc_list, email_queue_list, customers_list):
|
||||
if isinstance(doc_list, basestring):
|
||||
doc_list = json.loads(doc_list)
|
||||
|
||||
if isinstance(email_queue_list, basestring):
|
||||
email_queue = json.loads(email_queue_list)
|
||||
|
||||
if isinstance(customers_list, basestring):
|
||||
customers = json.loads(customers_list)
|
||||
|
||||
customers = make_customer_and_address(customers)
|
||||
name_list = []
|
||||
for docs in doc_list:
|
||||
for name, doc in docs.items():
|
||||
@ -281,13 +300,49 @@ def make_invoice(doc_list, email_queue_list):
|
||||
email_queue = make_email_queue(email_queue)
|
||||
return {
|
||||
'invoice': name_list,
|
||||
'email_queue': email_queue
|
||||
'email_queue': email_queue,
|
||||
'customers': customers
|
||||
}
|
||||
|
||||
def validate_records(doc):
|
||||
validate_customer(doc)
|
||||
validate_item(doc)
|
||||
|
||||
def make_customer_and_address(customers):
|
||||
customer_list = []
|
||||
for name, data in customers.items():
|
||||
if not frappe.db.exists('Customer', name):
|
||||
name = add_customer(name)
|
||||
data = json.loads(data)
|
||||
make_address(data, name)
|
||||
customer_list.append(name)
|
||||
return customer_list
|
||||
|
||||
def add_customer(name):
|
||||
customer_doc = frappe.new_doc('Customer')
|
||||
customer_doc.customer_name = name
|
||||
customer_doc.customer_type = 'Company'
|
||||
customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group')
|
||||
customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory')
|
||||
customer_doc.flags.ignore_mandatory = True
|
||||
customer_doc.save(ignore_permissions = True)
|
||||
frappe.db.commit()
|
||||
|
||||
def make_address(args, customer):
|
||||
if args.get('name'):
|
||||
address = frappe.get_doc('Address', args.get('name'))
|
||||
address.is_primary_address = 1
|
||||
address.is_shipping_address = 1
|
||||
else:
|
||||
address = frappe.new_doc('Address')
|
||||
address.country = frappe.db.get_value('Company', args.get('company'), 'country')
|
||||
address.append('links',{
|
||||
'link_doctype': 'Customer',
|
||||
'link_name': customer
|
||||
})
|
||||
|
||||
address.update(args)
|
||||
address.save(ignore_permissions = True)
|
||||
|
||||
def make_email_queue(email_queue):
|
||||
name_list = []
|
||||
for key, data in email_queue.items():
|
||||
@ -304,39 +359,6 @@ def make_email_queue(email_queue):
|
||||
|
||||
return name_list
|
||||
|
||||
def validate_customer(doc):
|
||||
if not frappe.db.exists('Customer', doc.get('customer')):
|
||||
customer_doc = frappe.new_doc('Customer')
|
||||
customer_doc.customer_name = doc.get('customer')
|
||||
customer_doc.customer_type = 'Company'
|
||||
customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group')
|
||||
customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory')
|
||||
customer_doc.flags.ignore_mandatory = True
|
||||
customer_doc.save(ignore_permissions = True)
|
||||
frappe.db.commit()
|
||||
doc['customer'] = customer_doc.name
|
||||
if doc.get('contact_details'):
|
||||
args = json.loads(doc.get("contact_details"))
|
||||
make_address(doc, args, customer_doc.name)
|
||||
|
||||
def make_address(doc, args, customer):
|
||||
if args.get("address_line1"):
|
||||
address = frappe.new_doc('Address')
|
||||
address.address_line1 = args.get('address_line1')
|
||||
address.address_line2 = args.get('address_line2')
|
||||
address.city = args.get('city')
|
||||
address.state = args.get('state')
|
||||
address.zip_code = args.get('zip_code')
|
||||
address.email_id = args.get('email_id')
|
||||
address.flags.ignore_mandatory = True
|
||||
address.country = frappe.db.get_value('Company', doc.get('company'), 'country')
|
||||
address.append('links',{
|
||||
'link_doctype': 'Customer',
|
||||
'link_name': customer
|
||||
})
|
||||
address.save(ignore_permissions = True)
|
||||
frappe.db.commit()
|
||||
|
||||
def validate_item(doc):
|
||||
for item in doc.get('items'):
|
||||
if not frappe.db.exists('Item', item.get('item_code')):
|
||||
|
@ -154,6 +154,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
|
||||
get_customers_details: function () {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('customer_details')) || {};
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
|
||||
dialog_actions: function () {
|
||||
var me = this;
|
||||
|
||||
@ -289,6 +297,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.serial_no_data = r.message.serial_no_data;
|
||||
this.batch_no_data = r.message.batch_no_data;
|
||||
this.tax_data = r.message.tax_data;
|
||||
this.address = r.message.address || {};
|
||||
this.price_list_data = r.message.price_list_data;
|
||||
this.bin_data = r.message.bin_data;
|
||||
this.pricing_rules = r.message.pricing_rules;
|
||||
@ -406,6 +415,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
me.items = me.get_items();
|
||||
me.make_item_list();
|
||||
})
|
||||
|
||||
this.wrapper.find(".edit-customer-btn").on("click", function() {
|
||||
me.update_customer()
|
||||
})
|
||||
},
|
||||
|
||||
make_list_customers: function () {
|
||||
@ -609,7 +622,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
item: function (item, input) {
|
||||
var d = item;
|
||||
var html = "<span>" + __(d.label || d.value) + "</span>";
|
||||
var html = "<span>" + __(d.label || d.value) + "</span>\
|
||||
<span class='link-btn'>\
|
||||
<a class='btn-open no-decoration' title='" + __('Open Link') + "'>\
|
||||
<i class='octicon octicon-arrow-right'></i></a>\
|
||||
</span>";
|
||||
return $('<li></li>')
|
||||
.data('item.autocomplete', d)
|
||||
.html('<a><p>' + html + '</p></a>')
|
||||
@ -631,7 +648,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
+ __("Create a new Customer")
|
||||
+ "</span>",
|
||||
value: 'is_action',
|
||||
action: me.new_customer
|
||||
action: me.add_customer
|
||||
});
|
||||
this.party_field.awesomeplete.list = customers;
|
||||
|
||||
@ -652,11 +669,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
me.refresh();
|
||||
me.set_focus();
|
||||
})
|
||||
.on('change', function (e) {
|
||||
if (!e.originalEvent.text) {
|
||||
me.frm.doc.customer = $(this).val();
|
||||
}
|
||||
})
|
||||
.on('focus', function (e) {
|
||||
$(e.target).val('').trigger('input');
|
||||
})
|
||||
@ -670,7 +682,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
});
|
||||
},
|
||||
|
||||
new_customer: function () {
|
||||
add_customer: function() {
|
||||
this.frm.doc.customer = "";
|
||||
this.update_customer()
|
||||
},
|
||||
|
||||
update_customer: function () {
|
||||
var me = this;
|
||||
if (!this.connection_status) return;
|
||||
|
||||
@ -696,7 +713,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
{
|
||||
"label": __("Contact Number"),
|
||||
"fieldname": "contact_no",
|
||||
"fieldname": "phone",
|
||||
"fieldtype": "Data"
|
||||
},
|
||||
{
|
||||
@ -712,6 +729,11 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
"fieldname": "address_line2",
|
||||
"fieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"label": __("Fax"),
|
||||
"fieldname": "fax",
|
||||
"fieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
@ -727,13 +749,20 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
{
|
||||
"label": __("ZIP Code"),
|
||||
"fieldname": "zip_code",
|
||||
"fieldname": "pincode",
|
||||
"fieldtype": "Data"
|
||||
},
|
||||
{
|
||||
"label": __("ZIP Code"),
|
||||
"hidden": 1,
|
||||
"fieldname": "name",
|
||||
"fieldtype": "Data"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
this.customer_doc.show()
|
||||
this.render_address_data()
|
||||
|
||||
this.customer_doc.set_primary_action(__("Save"), function () {
|
||||
me.make_offline_customer();
|
||||
@ -741,18 +770,45 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
});
|
||||
},
|
||||
|
||||
render_address_data: function() {
|
||||
var me = this;
|
||||
this.address_data = this.address[this.frm.doc.customer] || this.get_address_from_localstorage();
|
||||
prompt_obj = me.customer_doc.fields_dict;
|
||||
$.each(this.address_data, function(key, value){
|
||||
if(prompt_obj[key] && key!='name') {
|
||||
prompt_obj[key].$input.val(value)
|
||||
}
|
||||
})
|
||||
|
||||
if(!prompt_obj.full_name.$input.val()) {
|
||||
prompt_obj.full_name.$input.val(this.frm.doc.customer)
|
||||
}
|
||||
},
|
||||
|
||||
get_address_from_localstorage: function() {
|
||||
this.address_details = this.get_customers_details()
|
||||
return this.address_details[this.frm.doc.customer]
|
||||
},
|
||||
|
||||
make_offline_customer: function() {
|
||||
this.frm.doc.customer = this.customer_doc.get_values().full_name;
|
||||
this.frm.doc.contact_details = JSON.stringify(this.customer_doc.get_values());
|
||||
this.frm.doc.customer = this.frm.doc.customer || this.customer_doc.get_values().full_name;
|
||||
this.customer_details[this.frm.doc.customer] = this.get_prompt_details();
|
||||
this.party_field.$input.val(this.frm.doc.customer);
|
||||
this.customers.push({
|
||||
name: this.frm.doc.customer,
|
||||
customer_name: this.frm.doc.customer
|
||||
});
|
||||
|
||||
this.update_customer_in_localstorage()
|
||||
this.update_customer_in_localstorage()
|
||||
this.customer_doc.hide()
|
||||
},
|
||||
|
||||
get_prompt_details: function() {
|
||||
this.prompt_details = this.customer_doc.get_values();
|
||||
this.prompt_details['country'] = this.frm.doc.country;
|
||||
return JSON.stringify(this.prompt_details)
|
||||
},
|
||||
|
||||
update_customer_data: function (doc) {
|
||||
var me = this;
|
||||
this.frm.doc.customer = doc.label || doc.name;
|
||||
@ -1368,20 +1424,24 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
var me = this;
|
||||
this.si_docs = this.get_submitted_invoice() || [];
|
||||
this.email_queue_list = this.get_email_queue() || {};
|
||||
this.customers_list = this.get_customers_details() || {};
|
||||
|
||||
if (this.si_docs.length || this.email_queue_list) {
|
||||
frappe.call({
|
||||
method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
|
||||
args: {
|
||||
doc_list: me.si_docs,
|
||||
email_queue_list: me.email_queue_list
|
||||
email_queue_list: me.email_queue_list,
|
||||
customers_list: me.customers_list
|
||||
},
|
||||
callback: function (r) {
|
||||
if (r.message) {
|
||||
me.removed_items = r.message.invoice;
|
||||
me.removed_email = r.message.email_queue
|
||||
me.removed_customers = r.message.customers
|
||||
me.remove_doc_from_localstorage();
|
||||
me.remove_email_queue_from_localstorage();
|
||||
me.remove_customer_from_localstorage();
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -1437,6 +1497,19 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
|
||||
remove_customer_from_localstorage: function() {
|
||||
var me = this;
|
||||
this.customer_details = this.get_customers_details()
|
||||
if (this.removed_customers) {
|
||||
$.each(this.customers_list, function (index, data) {
|
||||
if (in_list(me.removed_customers, index)) {
|
||||
delete me.customer_details[index]
|
||||
}
|
||||
})
|
||||
this.update_customer_in_localstorage();
|
||||
}
|
||||
},
|
||||
|
||||
validate: function () {
|
||||
var me = this;
|
||||
this.customer_validate();
|
||||
@ -1621,5 +1694,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
|
||||
return this.actual_qty
|
||||
},
|
||||
|
||||
update_customer_in_localstorage: function() {
|
||||
var me = this;
|
||||
try {
|
||||
localStorage.setItem('customer_details', JSON.stringify(this.customer_details));
|
||||
} catch (e) {
|
||||
frappe.throw(__("LocalStorage is full , did not save"))
|
||||
}
|
||||
}
|
||||
})
|
@ -1,23 +1,68 @@
|
||||
<div class="pos">
|
||||
</div>
|
||||
<div class="totals-area">
|
||||
<div class="row pos-bill-row net-total-area">
|
||||
<div class="col-xs-6"><h6 class="text-muted">{%= __("Net Total") %}</h6></div>
|
||||
<div class="col-xs-6"><h6 class="net-total text-right"></h6></div>
|
||||
</div>
|
||||
<div class="row pos-bill-row tax-area hide">
|
||||
<div class="col-xs-12 text-muted">
|
||||
<h6>{%= __("Taxes") %}</h6>
|
||||
<div class="tax-table small"></div>
|
||||
<div class="row">
|
||||
<div class="col-sm-5 pos-bill-wrapper">
|
||||
<div class="col-sm-12"><h6 class="form-section-heading uppercase">Item Cart</h6></div>
|
||||
<div class="pos-bill">
|
||||
<div class="item-cart">
|
||||
<div class="pos-list-row pos-bill-header text-muted h6">
|
||||
<span class="cell subject">
|
||||
<!--<input class="list-select-all" type="checkbox" title="{%= __("Select All") %}">-->
|
||||
{{ __("Item Name")}}
|
||||
</span>
|
||||
<span class="cell text-right">{{ __("Quantity") }}</span>
|
||||
<span class="cell text-right">{{ __("Discount") }}</span>
|
||||
<span class="cell text-right">{{ __("Rate") }}</span>
|
||||
</div>
|
||||
<div class="item-cart-items">
|
||||
<div class="no-items-message text-extra-muted">
|
||||
<span class="text-center">
|
||||
<i class="fa fa-4x fa-shopping-cart"></i>
|
||||
<p>Tap items to add them here</p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if (apply_discount_on) { %}
|
||||
<div class="row pos-bill-row discount-amount-area">
|
||||
<div class="col-xs-6"><h6 class="text-muted">{%= __("Discount") %}</h6></div>
|
||||
<div class="col-xs-3 discount-field-col">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">%</span>
|
||||
<input type="text" class="form-control discount-percentage text-right">
|
||||
<div class="items">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="totals-area">
|
||||
<div class="pos-list-row net-total-area hide">
|
||||
<div class="cell subject"></div>
|
||||
<div class="cell"></div>
|
||||
<div class="cell text-right">{%= __("Net Total") %}</div>
|
||||
<div class="cell net-total text-right"></div>
|
||||
</div>
|
||||
<div class="pos-list-row tax-area hide">
|
||||
<div class="cell subject"></div>
|
||||
<div class="cell"></div>
|
||||
<div class="cell text-muted">{%= __("Taxes") %}</div>
|
||||
<div class="cell text-right tax-table"></div>
|
||||
</div>
|
||||
{% if (apply_discount_on) { %}
|
||||
<div class="pos-list-row discount-amount-area hide">
|
||||
<div class="cell text-muted">{%= __("Discount") %}</div>
|
||||
<div class="cell discount-field-col">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">%</span>
|
||||
<input type="text" class="form-control discount-percentage text-right">
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell discount-field-col">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-addon">{%= get_currency_symbol(currency) %}</span>
|
||||
<input type="text" class="form-control discount-amount text-right" placeholder="{%= 0.00 %}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% } %}
|
||||
<div class="pos-list-row grand-total-area" style="border-bottom:1px solid #d1d8dd;">
|
||||
<div class="cell subject"></div>
|
||||
<div class="cell text-right bold">{%= __("Grand Total") %}</div>
|
||||
<div class="cell grand-total text-right lead"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 30px">
|
||||
<div class="col-xs-6 selected-item">
|
||||
|
||||
</div>
|
||||
<div class="col-xs-6 numeric_keypad" style="display:none">
|
||||
@ -38,44 +83,33 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 pos-items-section">
|
||||
<div class="col-sm-5 list-customers">
|
||||
|
||||
</div>
|
||||
<div class="col-sm-7 pos-items-section">
|
||||
<div class="col-sm-12"><h6 class="form-section-heading uppercase">Stock Items</h6></div>
|
||||
<div class="row pos-item-area">
|
||||
|
||||
</div>
|
||||
<span id="customer-results" style="color:#68a;"></span>
|
||||
<div class="row pos-item-toolbar hide">
|
||||
<div class="search-item-group col-xs-5 hide"></div>
|
||||
<div class="search-item col-xs-7 hide"></div>
|
||||
<!--<div class="search-item-group col-xs-5"></div>-->
|
||||
<!--<div class="search-item col-xs-7"></div>-->
|
||||
</div>
|
||||
<div class="item-list-area">
|
||||
<div class="pos-list-row pos-bill-header text-muted h6">
|
||||
<div class="cell subject">All Item Groups</div>
|
||||
<div class="cell"></div>
|
||||
<div class="cell"></div>
|
||||
<div class="cell"></div>
|
||||
<div class="cell subject search-item-group">
|
||||
<div class="dropdown">
|
||||
<a class="text-muted dropdown-toggle" data-toggle="dropdown"><span class="dropdown-text">All Item Groups</span><i class="caret"></i></a>
|
||||
<ul class="dropdown-menu">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cell search-item"></div>
|
||||
</div>
|
||||
<<<<<<< 889e91312e9cfe10a2fd38ba7864e7c7546f4de8
|
||||
<div class="app-listing item-list image-view-container three-column">
|
||||
<div class="app-listing item-list image-view-container">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
=======
|
||||
<span id="customer-results" style="color:#68a;"></span>
|
||||
<div class="row pos-item-toolbar">
|
||||
<div class="search-item-group col-xs-5"></div>
|
||||
<div class="search-item col-xs-7"></div>
|
||||
</div>
|
||||
<div class="item-list-area" style="auto">
|
||||
<div class="app-listing item-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="text-right list-paging-area">
|
||||
<button class="btn btn-default btn-more btn-sm" style="margin:5px 20px">{{ __("More") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
>>>>>>> offline email for POS
|
||||
</div>
|
||||
</div>
|
Loading…
x
Reference in New Issue
Block a user