Provision to edit customer and address details

This commit is contained in:
Rohit Waghchaure 2017-03-07 14:01:04 +05:30
parent adcb3c62fa
commit 1312fe31a9
3 changed files with 234 additions and 96 deletions

View File

@ -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')):

View File

@ -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"))
}
}
})

View File

@ -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>