Merge branch 'develop' into develop

This commit is contained in:
Deepesh Garg 2019-10-20 22:04:30 +05:30 committed by GitHub
commit dc694597f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1809 additions and 2792 deletions

View File

@ -0,0 +1,35 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Coupon Code', {
coupon_name:function(frm){
if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code");
}
},
coupon_type:function(frm){
if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code");
}
},
make_coupon_code: function(frm) {
var coupon_name=frm.doc.coupon_name;
var coupon_code;
if (frm.doc.coupon_type=='Gift Card') {
coupon_code=Math.random().toString(12).substring(2, 12).toUpperCase();
}
else if(frm.doc.coupon_type=='Promotional'){
coupon_name=coupon_name.replace(/\s/g,'');
coupon_code=coupon_name.toUpperCase().slice(0,8);
}
frm.doc.coupon_code=coupon_code;
frm.refresh_field('coupon_code');
},
refresh: function(frm) {
if (frm.doc.pricing_rule) {
frm.add_custom_button(__("Add/Edit Coupon Conditions"), function(){
frappe.set_route("Form", "Pricing Rule", frm.doc.pricing_rule);
});
}
}
});

View File

@ -0,0 +1,175 @@
{
"allow_import": 1,
"autoname": "field:coupon_name",
"creation": "2018-01-22 14:34:39.701832",
"doctype": "DocType",
"document_type": "Other",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"coupon_name",
"coupon_type",
"customer",
"column_break_4",
"coupon_code",
"pricing_rule",
"uses",
"valid_from",
"valid_upto",
"maximum_use",
"used",
"column_break_11",
"description",
"amended_from"
],
"fields": [
{
"fieldname": "coupon_name",
"fieldtype": "Data",
"label": "Coupon Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "coupon_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Coupon Type",
"options": "Promotional\nGift Card",
"reqd": 1
},
{
"depends_on": "eval: doc.coupon_type == \"Gift Card\"",
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
"options": "Customer"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"description": "To be used to get discount",
"fieldname": "coupon_code",
"fieldtype": "Data",
"label": "Coupon Code",
"no_copy": 1,
"set_only_once": 1,
"unique": 1
},
{
"fieldname": "pricing_rule",
"fieldtype": "Link",
"label": "Pricing Rule",
"options": "Pricing Rule"
},
{
"fieldname": "uses",
"fieldtype": "Section Break",
"label": "Uses"
},
{
"fieldname": "valid_from",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Valid From"
},
{
"fieldname": "valid_upto",
"fieldtype": "Date",
"label": "Valid Upto"
},
{
"depends_on": "eval: doc.coupon_type == \"Promotional\"",
"fieldname": "maximum_use",
"fieldtype": "Int",
"label": "Maximum Use"
},
{
"default": "0",
"fieldname": "used",
"fieldtype": "Int",
"label": "Used",
"no_copy": 1,
"read_only": 1
},
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Coupon Description"
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"label": "Amended From",
"no_copy": 1,
"options": "Coupon Code",
"print_hide": 1,
"read_only": 1
}
],
"modified": "2019-10-15 14:12:22.686986",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Website Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "coupon_name",
"track_changes": 1
}

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, 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.model.document import Document
from frappe.utils import (strip)
class CouponCode(Document):
def autoname(self):
self.coupon_name = strip(self.coupon_name)
self.name = self.coupon_name
if not self.coupon_code:
if self.coupon_type == "Promotional":
self.coupon_code =''.join([i for i in self.coupon_name if not i.isdigit()])[0:8].upper()
elif self.coupon_type == "Gift Card":
self.coupon_code = frappe.generate_hash()[:10].upper()
def validate(self):
if self.coupon_type == "Gift Card":
self.maximum_use = 1
if not self.customer:
frappe.throw(_("Please select the customer."))

View File

@ -0,0 +1,23 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Coupon Code", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Coupon Code
() => frappe.tests.make('Coupon Code', [
// values to be set
{key: 'value'}
]),
() => {
assert.equal(cur_frm.doc.key, 'value');
},
() => done()
]);
});

View File

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.stock.get_item_details import get_item_details
from frappe.test_runner import make_test_objects
def test_create_test_data():
frappe.set_user("Administrator")
# create test item
if not frappe.db.exists("Item","_Test Tesla Car"):
item = frappe.get_doc({
"description": "_Test Tesla Car",
"doctype": "Item",
"has_batch_no": 0,
"has_serial_no": 0,
"inspection_required": 0,
"is_stock_item": 1,
"opening_stock":100,
"is_sub_contracted_item": 0,
"item_code": "_Test Tesla Car",
"item_group": "_Test Item Group",
"item_name": "_Test Tesla Car",
"apply_warehouse_wise_reorder_level": 0,
"warehouse":"_Test Warehouse - _TC",
"gst_hsn_code": "999800",
"valuation_rate": 5000,
"standard_rate":5000,
"item_defaults": [{
"company": "_Test Company",
"default_warehouse": "_Test Warehouse - _TC",
"default_price_list":"_Test Price List",
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"buying_cost_center": "_Test Cost Center - _TC",
"selling_cost_center": "_Test Cost Center - _TC",
"income_account": "Sales - _TC"
}],
"show_in_website": 1,
"route":"-test-tesla-car",
"website_warehouse": "_Test Warehouse - _TC"
})
item.insert()
# create test item price
item_price = frappe.get_list('Item Price', filters={'item_code': '_Test Tesla Car', 'price_list': '_Test Price List'}, fields=['name'])
if len(item_price)==0:
item_price = frappe.get_doc({
"doctype": "Item Price",
"item_code": "_Test Tesla Car",
"price_list": "_Test Price List",
"price_list_rate": 5000
})
item_price.insert()
# create test item pricing rule
if not frappe.db.exists("Pricing Rule","_Test Pricing Rule for _Test Item"):
item_pricing_rule = frappe.get_doc({
"doctype": "Pricing Rule",
"title": "_Test Pricing Rule for _Test Item",
"apply_on": "Item Code",
"items": [{
"item_code": "_Test Tesla Car"
}],
"warehouse":"_Test Warehouse - _TC",
"coupon_code_based":1,
"selling": 1,
"rate_or_discount": "Discount Percentage",
"discount_percentage": 30,
"company": "_Test Company",
"currency":"INR",
"for_price_list":"_Test Price List"
})
item_pricing_rule.insert()
# create test item sales partner
if not frappe.db.exists("Sales Partner","_Test Coupon Partner"):
sales_partner = frappe.get_doc({
"doctype": "Sales Partner",
"partner_name":"_Test Coupon Partner",
"commission_rate":2,
"referral_code": "COPART"
})
sales_partner.insert()
# create test item coupon code
if not frappe.db.exists("Coupon Code","SAVE30"):
coupon_code = frappe.get_doc({
"doctype": "Coupon Code",
"coupon_name":"SAVE30",
"coupon_code":"SAVE30",
"pricing_rule": "_Test Pricing Rule for _Test Item",
"valid_from": "2014-01-01",
"maximum_use":1,
"used":0
})
coupon_code.insert()
class TestCouponCode(unittest.TestCase):
def setUp(self):
test_create_test_data()
def tearDown(self):
frappe.set_user("Administrator")
def test_1_check_coupon_code_used_before_so(self):
coupon_code = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
# reset used coupon code count
coupon_code.used=0
coupon_code.save()
# check no coupon code is used before sales order is made
self.assertEqual(coupon_code.get("used"),0)
def test_2_sales_order_with_coupon_code(self):
so = make_sales_order(customer="_Test Customer",selling_price_list="_Test Price List",item_code="_Test Tesla Car", rate=5000,qty=1, do_not_submit=True)
so = frappe.get_doc('Sales Order', so.name)
# check item price before coupon code is applied
self.assertEqual(so.items[0].rate, 5000)
so.coupon_code='SAVE30'
so.sales_partner='_Test Coupon Partner'
so.save()
# check item price after coupon code is applied
self.assertEqual(so.items[0].rate, 3500)
so.submit()
def test_3_check_coupon_code_used_after_so(self):
doc = frappe.get_doc("Coupon Code", frappe.db.get_value("Coupon Code", {"coupon_name":"SAVE30"}))
# check no coupon code is used before sales order is made
self.assertEqual(doc.get("used"),1)

File diff suppressed because it is too large Load Diff

View File

@ -249,6 +249,9 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other: if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
continue continue
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
return item_details
if (not pricing_rule.validate_applied_rule and if (not pricing_rule.validate_applied_rule and
pricing_rule.price_or_product_discount == "Price"): pricing_rule.price_or_product_discount == "Price"):
apply_price_discount_pricing_rule(pricing_rule, item_details, args) apply_price_discount_pricing_rule(pricing_rule, item_details, args)

View File

@ -531,4 +531,32 @@ def validate_pricing_rule_for_different_cond(doc):
for d in doc.get("items"): for d in doc.get("items"):
validate_pricing_rule_on_items(doc, d, True) validate_pricing_rule_on_items(doc, d, True)
return doc return doc
def validate_coupon_code(coupon_name):
from frappe.utils import today,getdate
coupon=frappe.get_doc("Coupon Code",coupon_name)
if coupon.valid_from:
if coupon.valid_from > getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has not started"))
elif coupon.valid_upto:
if coupon.valid_upto < getdate(today()) :
frappe.throw(_("Sorry,coupon code validity has expired"))
elif coupon.used>=coupon.maximum_use:
frappe.throw(_("Sorry,coupon code are exhausted"))
else:
return
def update_coupon_code_count(coupon_name,transaction_type):
coupon=frappe.get_doc("Coupon Code",coupon_name)
if coupon:
if transaction_type=='used':
if coupon.used<coupon.maximum_use:
coupon.used=coupon.used+1
coupon.save(ignore_permissions=True)
else:
frappe.throw(_("{0} Coupon used are {1}. Allowed quantity is exhausted").format(coupon.coupon_code,coupon.used))
elif transaction_type=='cancelled':
if coupon.used>0:
coupon.used=coupon.used-1
coupon.save(ignore_permissions=True)

View File

@ -12,7 +12,7 @@ from frappe.utils import (add_days, getdate, formatdate, date_diff,
from frappe.contacts.doctype.address.address import (get_address_display, from frappe.contacts.doctype.address.address import (get_address_display,
get_default_address, get_company_address) get_default_address, get_company_address)
from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact from frappe.contacts.doctype.contact.contact import get_contact_details, get_default_contact
from erpnext.exceptions import PartyFrozen, InvalidAccountCurrency from erpnext.exceptions import PartyFrozen, PartyDisabled, InvalidAccountCurrency
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
from erpnext import get_company_currency from erpnext import get_company_currency
@ -446,7 +446,9 @@ def validate_party_frozen_disabled(party_type, party_name):
if party_type and party_name: if party_type and party_name:
if party_type in ("Customer", "Supplier"): if party_type in ("Customer", "Supplier"):
party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True) party = frappe.get_cached_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)
if party.get("is_frozen"): if party.disabled:
frappe.throw(_("{0} {1} is disabled").format(party_type, party_name), PartyDisabled)
elif party.get("is_frozen"):
frozen_accounts_modifier = frappe.db.get_single_value( 'Accounts Settings', 'frozen_accounts_modifier') frozen_accounts_modifier = frappe.db.get_single_value( 'Accounts Settings', 'frozen_accounts_modifier')
if not frozen_accounts_modifier in frappe.get_roles(): if not frozen_accounts_modifier in frappe.get_roles():
frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen) frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen)

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe, unittest import frappe, unittest
from erpnext.accounts.party import get_due_date from erpnext.accounts.party import get_due_date
from erpnext.exceptions import PartyDisabled
from frappe.test_runner import make_test_records from frappe.test_runner import make_test_records
test_dependencies = ['Payment Term', 'Payment Terms Template'] test_dependencies = ['Payment Term', 'Payment Terms Template']
@ -70,7 +71,7 @@ class TestSupplier(unittest.TestCase):
po = create_purchase_order(do_not_save=True) po = create_purchase_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, po.save) self.assertRaises(PartyDisabled, po.save)
frappe.db.set_value("Supplier", "_Test Supplier", "disabled", 0) frappe.db.set_value("Supplier", "_Test Supplier", "disabled", 0)

View File

@ -5,3 +5,4 @@ import frappe
class PartyFrozen(frappe.ValidationError): pass class PartyFrozen(frappe.ValidationError): pass
class InvalidAccountCurrency(frappe.ValidationError): pass class InvalidAccountCurrency(frappe.ValidationError): pass
class InvalidCurrency(frappe.ValidationError): pass class InvalidCurrency(frappe.ValidationError): pass
class PartyDisabled(frappe.ValidationError):pass

View File

@ -234,7 +234,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' \ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' \
data-pts='°C or °F' data-title='Temperature'>Temperature</a>\ data-pts='°C or °F' data-title='Temperature'>Temperature</a>\
<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' \ <a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' \
data-pts='bmi' data-title='BMI'>BMI</a></div>"; data-pts='' data-title='BMI'>BMI</a></div>";
me.page.main.find(".show_chart_btns").html(show_chart_btns_html); me.page.main.find(".show_chart_btns").html(show_chart_btns_html);
var data = r.message; var data = r.message;
let labels = [], datasets = []; let labels = [], datasets = [];
@ -275,7 +275,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
datasets.push({name: "Heart Rate / Pulse", values: pulse, chartType:'line'}); datasets.push({name: "Heart Rate / Pulse", values: pulse, chartType:'line'});
datasets.push({name: "Respiratory Rate", values: respiratory_rate, chartType:'line'}); datasets.push({name: "Respiratory Rate", values: respiratory_rate, chartType:'line'});
} }
new Chart( ".patient_vital_charts", { new frappe.Chart( ".patient_vital_charts", {
data: { data: {
labels: labels, labels: labels,
datasets: datasets datasets: datasets
@ -283,7 +283,7 @@ var show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
title: title, title: title,
type: 'axis-mixed', // 'axis-mixed', 'bar', 'line', 'pie', 'percentage' type: 'axis-mixed', // 'axis-mixed', 'bar', 'line', 'pie', 'percentage'
height: 150, height: 200,
colors: ['purple', '#ffa3ef', 'light-blue'], colors: ['purple', '#ffa3ef', 'light-blue'],
tooltipOptions: { tooltipOptions: {

View File

@ -1233,7 +1233,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
"is_return": cint(me.frm.doc.is_return), "is_return": cint(me.frm.doc.is_return),
"update_stock": in_list(['Sales Invoice', 'Purchase Invoice'], me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0, "update_stock": in_list(['Sales Invoice', 'Purchase Invoice'], me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0,
"conversion_factor": me.frm.doc.conversion_factor, "conversion_factor": me.frm.doc.conversion_factor,
"pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '' "pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '',
"coupon_code": me.frm.doc.coupon_code
}; };
}, },
@ -1742,6 +1743,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse); frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
}); });
} }
},
coupon_code: function() {
var me = this;
frappe.run_serially([
() => this.frm.doc.ignore_pricing_rule=1,
() => me.ignore_pricing_rule(),
() => this.frm.doc.ignore_pricing_rule=0,
() => me.apply_pricing_rule()
]);
} }
}); });

View File

@ -5,6 +5,19 @@
frappe.provide("erpnext.shopping_cart"); frappe.provide("erpnext.shopping_cart");
var shopping_cart = erpnext.shopping_cart; var shopping_cart = erpnext.shopping_cart;
var getParams = function (url) {
var params = [];
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
};
frappe.ready(function() { frappe.ready(function() {
var full_name = frappe.session && frappe.session.user_fullname; var full_name = frappe.session && frappe.session.user_fullname;
// update user // update user
@ -12,7 +25,32 @@ frappe.ready(function() {
$('.navbar li[data-label="User"] a') $('.navbar li[data-label="User"] a')
.html('<i class="fa fa-fixed-width fa fa-user"></i> ' + full_name); .html('<i class="fa fa-fixed-width fa fa-user"></i> ' + full_name);
} }
// set coupon code and sales partner code
var url_args = getParams(window.location.href);
var referral_coupon_code = url_args['cc'];
var referral_sales_partner = url_args['sp'];
var d = new Date();
// expires within 30 minutes
d.setTime(d.getTime() + (0.02 * 24 * 60 * 60 * 1000));
var expires = "expires="+d.toUTCString();
if (referral_coupon_code) {
document.cookie = "referral_coupon_code=" + referral_coupon_code + ";" + expires + ";path=/";
}
if (referral_sales_partner) {
document.cookie = "referral_sales_partner=" + referral_sales_partner + ";" + expires + ";path=/";
}
referral_coupon_code=frappe.get_cookie("referral_coupon_code");
referral_sales_partner=frappe.get_cookie("referral_sales_partner");
if (referral_coupon_code && $(".tot_quotation_discount").val()==undefined ) {
$(".txtcoupon").val(referral_coupon_code);
}
if (referral_sales_partner) {
$(".txtreferral_sales_partner").val(referral_sales_partner);
}
// update login // update login
shopping_cart.show_shoppingcart_dropdown(); shopping_cart.show_shoppingcart_dropdown();
shopping_cart.set_cart_count(); shopping_cart.set_cart_count();

View File

@ -0,0 +1,8 @@
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('DATEV Settings', {
// refresh: function(frm) {
// }
});

View File

@ -0,0 +1,105 @@
{
"autoname": "field:client",
"creation": "2019-08-13 23:56:34.259906",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"client",
"column_break_2",
"client_number",
"section_break_4",
"consultant",
"column_break_6",
"consultant_number"
],
"fields": [
{
"fieldname": "client",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Client",
"options": "Company",
"reqd": 1,
"unique": 1
},
{
"fieldname": "client_number",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Client ID",
"reqd": 1
},
{
"fieldname": "consultant",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Consultant",
"options": "Supplier"
},
{
"fieldname": "consultant_number",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Consultant ID",
"reqd": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
}
],
"modified": "2019-08-14 00:03:26.616460",
"modified_by": "Administrator",
"module": "Regional",
"name": "DATEV Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, 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 DATEVSettings(Document):
pass

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestDATEVSettings(unittest.TestCase):
pass

View File

@ -8,6 +8,7 @@ Provide a report and downloadable CSV according to the German DATEV format.
all required columns. Used to import the data into the DATEV Software. all required columns. Used to import the data into the DATEV Software.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime
import json import json
from six import string_types from six import string_types
import frappe import frappe
@ -17,24 +18,28 @@ import pandas as pd
def execute(filters=None): def execute(filters=None):
"""Entry point for frappe.""" """Entry point for frappe."""
validate_filters(filters) validate(filters)
result = get_gl_entries(filters, as_dict=0) result = get_gl_entries(filters, as_dict=0)
columns = get_columns() columns = get_columns()
return columns, result return columns, result
def validate_filters(filters): def validate(filters):
"""Make sure all mandatory filters are present.""" """Make sure all mandatory filters and settings are present."""
if not filters.get('company'): if not filters.get('company'):
frappe.throw(_('{0} is mandatory').format(_('Company'))) frappe.throw(_('<b>Company</b> is a mandatory filter.'))
if not filters.get('from_date'): if not filters.get('from_date'):
frappe.throw(_('{0} is mandatory').format(_('From Date'))) frappe.throw(_('<b>From Date</b> is a mandatory filter.'))
if not filters.get('to_date'): if not filters.get('to_date'):
frappe.throw(_('{0} is mandatory').format(_('To Date'))) frappe.throw(_('<b>To Date</b> is a mandatory filter.'))
try:
frappe.get_doc('DATEV Settings', filters.get('company'))
except frappe.DoesNotExistError:
frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
def get_columns(): def get_columns():
"""Return the list of columns that will be shown in query report.""" """Return the list of columns that will be shown in query report."""
@ -158,13 +163,84 @@ def get_gl_entries(filters, as_dict):
return gl_entries return gl_entries
def get_datev_csv(data): def get_datev_csv(data, filters):
""" """
Fill in missing columns and return a CSV in DATEV Format. Fill in missing columns and return a CSV in DATEV Format.
For automatic processing, DATEV requires the first line of the CSV file to
hold meta data such as the length of account numbers oder the category of
the data.
Arguments: Arguments:
data -- array of dictionaries data -- array of dictionaries
filters -- dict
""" """
header = [
# A = DATEV format
# DTVF = created by DATEV software,
# EXTF = created by other software
"EXTF",
# B = version of the DATEV format
# 141 = 1.41,
# 510 = 5.10,
# 720 = 7.20
"510",
# C = Data category
# 21 = Transaction batch (Buchungsstapel),
# 67 = Buchungstextkonstanten,
# 16 = Debitors/Creditors,
# 20 = Account names (Kontenbeschriftungen)
"21",
# D = Format name
# Buchungsstapel,
# Buchungstextkonstanten,
# Debitoren/Kreditoren,
# Kontenbeschriftungen
"Buchungsstapel",
# E = Format version (regarding format name)
"",
# F = Generated on
datetime.datetime.now().strftime("%Y%m%d"),
# G = Imported on -- stays empty
"",
# H = Origin (SV = other (?), RE = KARE)
"SV",
# I = Exported by
frappe.session.user,
# J = Imported by -- stays empty
"",
# K = Tax consultant number (Beraternummer)
frappe.get_value("DATEV Settings", filters.get("company"), "consultant_number") or "",
"",
# L = Tax client number (Mandantennummer)
frappe.get_value("DATEV Settings", filters.get("company"), "client_number") or "",
"",
# M = Start of the fiscal year (Wirtschaftsjahresbeginn)
frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"),
# N = Length of account numbers (Sachkontenlänge)
"4",
# O = Transaction batch start date (YYYYMMDD)
frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"),
# P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions")
"{} - {} Buchungsstapel".format(
frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy")
),
# R = Diktatkürzel
"",
# S = Buchungstyp
# 1 = Transaction batch (Buchungsstapel),
# 2 = Annual financial statement (Jahresabschluss)
"1",
# T = Rechnungslegungszweck
"",
# U = Festschreibung
"",
# V = Kontoführungs-Währungskennzeichen des Geldkontos
frappe.get_value("Company", filters.get("company"), "default_currency")
]
columns = [ columns = [
# All possible columns must tbe listed here, because DATEV requires them to # All possible columns must tbe listed here, because DATEV requires them to
# be present in the CSV. # be present in the CSV.
@ -324,9 +400,10 @@ def get_datev_csv(data):
data_df = pd.DataFrame.from_records(data) data_df = pd.DataFrame.from_records(data)
result = empty_df.append(data_df) result = empty_df.append(data_df)
result["Belegdatum"] = pd.to_datetime(result["Belegdatum"]) result['Belegdatum'] = pd.to_datetime(result['Belegdatum'])
return result.to_csv( header = ';'.join(header).encode('latin_1')
data = result.to_csv(
sep=b';', sep=b';',
# European decimal seperator # European decimal seperator
decimal=',', decimal=',',
@ -342,6 +419,7 @@ def get_datev_csv(data):
columns=columns columns=columns
) )
return header + b'\r\n' + data
@frappe.whitelist() @frappe.whitelist()
def download_datev_csv(filters=None): def download_datev_csv(filters=None):
@ -359,15 +437,9 @@ def download_datev_csv(filters=None):
if isinstance(filters, string_types): if isinstance(filters, string_types):
filters = json.loads(filters) filters = json.loads(filters)
validate_filters(filters) validate(filters)
data = get_gl_entries(filters, as_dict=1) data = get_gl_entries(filters, as_dict=1)
filename = 'DATEV_Buchungsstapel_{}-{}_bis_{}'.format( frappe.response['result'] = get_datev_csv(data, filters)
filters.get('company'), frappe.response['doctype'] = 'EXTF_Buchungsstapel'
filters.get('from_date'),
filters.get('to_date')
)
frappe.response['result'] = get_datev_csv(data)
frappe.response['doctype'] = filename
frappe.response['type'] = 'csv' frappe.response['type'] = 'csv'

View File

@ -8,7 +8,7 @@ import unittest
from erpnext.accounts.party import get_due_date from erpnext.accounts.party import get_due_date
from frappe.test_runner import make_test_records from frappe.test_runner import make_test_records
from erpnext.exceptions import PartyFrozen from erpnext.exceptions import PartyFrozen, PartyDisabled
from frappe.utils import flt from frappe.utils import flt
from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
from erpnext.tests.utils import create_test_contact_and_address from erpnext.tests.utils import create_test_contact_and_address
@ -178,7 +178,7 @@ class TestCustomer(unittest.TestCase):
so = make_sales_order(do_not_save=True) so = make_sales_order(do_not_save=True)
self.assertRaises(frappe.ValidationError, so.save) self.assertRaises(PartyDisabled, so.save)
frappe.db.set_value("Customer", "_Test Customer", "disabled", 0) frappe.db.set_value("Customer", "_Test Customer", "disabled", 0)

View File

@ -1904,7 +1904,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Additional Discount", "label": "Additional Discount and Coupon Code",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -1920,6 +1920,74 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "coupon_code",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Coupon Code",
"length": 0,
"no_copy": 0,
"options": "Coupon Code",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "referral_sales_partner",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Referral Sales Partner",
"length": 0,
"no_copy": 0,
"options": "Sales Partner",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -3263,7 +3331,7 @@
"istable": 0, "istable": 0,
"max_attachments": 1, "max_attachments": 1,
"menu_index": 0, "menu_index": 0,
"modified": "2019-06-26 01:00:21.545591", "modified": "2019-10-14 01:00:21.545591",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Quotation", "name": "Quotation",

View File

@ -142,6 +142,9 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
if customer: if customer:
target.customer = customer.name target.customer = customer.name
target.customer_name = customer.customer_name target.customer_name = customer.customer_name
if source.referral_sales_partner:
target.sales_partner=source.referral_sales_partner
target.commission_rate=frappe.get_value('Sales Partner', source.referral_sales_partner, 'commission_rate')
target.ignore_pricing_rule = 1 target.ignore_pricing_rule = 1
target.flags.ignore_permissions = ignore_permissions target.flags.ignore_permissions = ignore_permissions
target.run_method("set_missing_values") target.run_method("set_missing_values")

View File

@ -79,6 +79,7 @@
"loyalty_points", "loyalty_points",
"loyalty_amount", "loyalty_amount",
"section_break_48", "section_break_48",
"coupon_code",
"apply_discount_on", "apply_discount_on",
"base_discount_amount", "base_discount_amount",
"column_break_50", "column_break_50",
@ -678,7 +679,13 @@
"collapsible_depends_on": "discount_amount", "collapsible_depends_on": "discount_amount",
"fieldname": "section_break_48", "fieldname": "section_break_48",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Additional Discount" "label": "Additional Discount and Coupon Code"
},
{
"fieldname": "coupon_code",
"fieldtype": "Link",
"label": "Coupon Code",
"options": "Coupon Code"
}, },
{ {
"default": "Grand Total", "default": "Grand Total",
@ -1185,7 +1192,7 @@
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-10-10 08:46:07.540565", "modified": "2019-10-14 08:46:07.540565",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Sales Order", "name": "Sales Order",
@ -1262,4 +1269,4 @@
"title_field": "title", "title_field": "title",
"track_changes": 1, "track_changes": 1,
"track_seen": 1 "track_seen": 1
} }

View File

@ -46,6 +46,10 @@ class SalesOrder(SellingController):
self.validate_serial_no_based_delivery() self.validate_serial_no_based_delivery()
validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_order_reference) validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
validate_coupon_code(self.coupon_code)
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
make_packing_list(self) make_packing_list(self)
@ -177,6 +181,9 @@ class SalesOrder(SellingController):
self.update_blanket_order() self.update_blanket_order()
update_linked_doc(self.doctype, self.name, self.inter_company_order_reference) update_linked_doc(self.doctype, self.name, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
update_coupon_code_count(self.coupon_code,'used')
def on_cancel(self): def on_cancel(self):
super(SalesOrder, self).on_cancel() super(SalesOrder, self).on_cancel()
@ -195,7 +202,10 @@ class SalesOrder(SellingController):
self.update_blanket_order() self.update_blanket_order()
unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference) unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference)
if self.coupon_code:
from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
update_coupon_code_count(self.coupon_code,'cancelled')
def update_project(self): def update_project(self):
if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') != "Each Transaction": if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') != "Each Transaction":
return return

View File

@ -24,5 +24,11 @@ frappe.ui.form.on('Sales Partner', {
} }
} }
}; };
},
referral_code:function(frm){
if (frm.doc.referral_code) {
frm.doc.referral_code=frm.doc.referral_code.toUpperCase();
frm.refresh_field('referral_code');
}
} }
}); });

View File

@ -510,6 +510,73 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "column_break_16",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "To Track inbound purchase",
"fetch_if_empty": 0,
"fieldname": "referral_code",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Referral Code",
"length": 8,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -779,7 +846,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2019-03-21 16:26:45.447265", "modified": "2019-10-14 16:26:45.447265",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Sales Partner", "name": "Sales Partner",

View File

@ -537,3 +537,29 @@ def get_address_territory(address_name):
def show_terms(doc): def show_terms(doc):
return doc.tc_name return doc.tc_name
@frappe.whitelist(allow_guest=True)
def apply_coupon_code(applied_code,applied_referral_sales_partner):
quotation = True
if applied_code:
coupon_list=frappe.get_all('Coupon Code', filters={"docstatus": ("<", "2"), 'coupon_code':applied_code }, fields=['name'])
if coupon_list:
coupon_name=coupon_list[0].name
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
validate_coupon_code(coupon_name)
quotation = _get_cart_quotation()
quotation.coupon_code=coupon_name
quotation.flags.ignore_permissions = True
quotation.save()
if applied_referral_sales_partner:
sales_partner_list=frappe.get_all('Sales Partner', filters={'docstatus': 0, 'referral_code':applied_referral_sales_partner }, fields=['name'])
if sales_partner_list:
sales_partner_name=sales_partner_list[0].name
quotation.referral_sales_partner=sales_partner_name
quotation.flags.ignore_permissions = True
quotation.save()
else:
frappe.throw(_("Please enter valid coupon code !!"))
else:
frappe.throw(_("Please enter coupon code !!"))
return quotation

View File

@ -275,6 +275,40 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "show_apply_coupon_code_in_website",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Show Apply Coupon Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -679,7 +713,7 @@
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2019-01-26 13:54:24.575322", "modified": "2019-10-14 13:54:24.575322",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Shopping Cart", "module": "Shopping Cart",
"name": "Shopping Cart Settings", "name": "Shopping Cart Settings",

View File

@ -20,6 +20,7 @@ $.extend(shopping_cart, {
shopping_cart.bind_change_qty(); shopping_cart.bind_change_qty();
shopping_cart.bind_change_notes(); shopping_cart.bind_change_notes();
shopping_cart.bind_dropdown_cart_buttons(); shopping_cart.bind_dropdown_cart_buttons();
shopping_cart.bind_coupon_code();
}, },
bind_address_select: function() { bind_address_select: function() {
@ -193,6 +194,29 @@ $.extend(shopping_cart, {
} }
} }
}); });
},
bind_coupon_code: function() {
$(".bt-coupon").on("click", function() {
shopping_cart.apply_coupon_code(this);
});
},
apply_coupon_code: function(btn) {
return frappe.call({
type: "POST",
method: "erpnext.shopping_cart.cart.apply_coupon_code",
btn: btn,
args : {
applied_code : $('.txtcoupon').val(),
applied_referral_sales_partner: $('.txtreferral_sales_partner').val()
},
callback: function(r) {
if (r && r.message){
location.reload();
}
}
});
} }
}); });

View File

@ -4,6 +4,16 @@
{% set select_address = True %} {% set select_address = True %}
{% endif %} {% endif %}
{% set show_coupon_code = frappe.db.get_single_value('Shopping Cart Settings', 'show_apply_coupon_code_in_website') %}
{% if show_coupon_code == 1%}
<div class="mb-3">
<div class="row no-gutters">
<input type="text" class="txtcoupon form-control mr-3 w-25" placeholder="Enter Coupon Code" name="txtcouponcode" ></input>
<button class="btn btn-primary btn-sm bt-coupon">{{ _("Apply Coupon Code") }}</button>
<input type="hidden" class="txtreferral_sales_partner" placeholder="Enter Sales Partner" name="txtreferral_sales_partner" type="text"></input>
</div>
</div>
{% endif %}
<div class="mb-3" data-section="shipping-address"> <div class="mb-3" data-section="shipping-address">
<h6 class="text-uppercase">{{ _("Shipping Address") }}</h6> <h6 class="text-uppercase">{{ _("Shipping Address") }}</h6>
<div class="row no-gutters" data-fieldname="shipping_address_name"> <div class="row no-gutters" data-fieldname="shipping_address_name">

View File

@ -22,6 +22,71 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if doc.doctype == 'Quotation' %}
{% if doc.coupon_code %}
<tr>
<th class="text-right" colspan="2">
{{ _("Discount") }}
</th>
<th class="text-right tot_quotation_discount">
{% set tot_quotation_discount = [] %}
{%- for item in doc.items -%}
{% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
* item.discount_percentage) / 100)) %}{% endif %}
{% endfor %}
{{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
</th>
</tr>
{% endif %}
{% endif %}
{% if doc.doctype == 'Sales Order' %}
{% if doc.coupon_code %}
<tr>
<th class="text-right" colspan="2">
{{ _("Total Amount") }}
</th>
<th class="text-right">
<span>
{% set total_amount = [] %}
{%- for item in doc.items -%}
{% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %}
{% endfor %}
{{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }}
</span>
</th>
</tr>
<tr>
<th class="text-right" colspan="2">
{{ _("Applied Coupon Code") }}
</th>
<th class="text-right">
<span>
{%- for row in frappe.get_all(doctype="Coupon Code",
fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
<span>{{ row.coupon_code }}</span>
{% endfor %}
</span>
</th>
</tr>
<tr>
<th class="text-right" colspan="2">
{{ _("Discount") }}
</th>
<th class="text-right">
<span>
{% set tot_SO_discount = [] %}
{%- for item in doc.items -%}
{% if tot_SO_discount.append((((item.price_list_rate * item.qty)
* item.discount_percentage) / 100)) %}{% endif %}
{% endfor %}
{{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
</span>
</th>
</tr>
{% endif %}
{% endif %}
<tr> <tr>
<th class="text-right" colspan="2"> <th class="text-right" colspan="2">
{{ _("Grand Total") }} {{ _("Grand Total") }}

View File

@ -1,166 +1,196 @@
{ {
"accept_payment": 0, "accept_payment": 0,
"allow_comments": 0, "allow_comments": 0,
"allow_delete": 0, "allow_delete": 0,
"allow_edit": 1, "allow_edit": 1,
"allow_incomplete": 0, "allow_incomplete": 0,
"allow_multiple": 1, "allow_multiple": 1,
"allow_print": 0, "allow_print": 0,
"amount": 0.0, "amount": 0.0,
"creation": "2016-06-24 15:50:33.196990", "amount_based_on_field": 0,
"doc_type": "Address", "creation": "2016-06-24 15:50:33.196990",
"docstatus": 0, "doc_type": "Address",
"doctype": "Web Form", "docstatus": 0,
"idx": 0, "doctype": "Web Form",
"is_standard": 1, "idx": 0,
"login_required": 1, "is_standard": 1,
"max_attachment_size": 0, "login_required": 1,
"modified": "2016-12-07 04:17:02.020768", "max_attachment_size": 0,
"modified_by": "Administrator", "modified": "2019-10-15 06:55:30.405119",
"module": "Utilities", "modified_by": "Administrator",
"name": "addresses", "module": "Utilities",
"owner": "Administrator", "name": "addresses",
"published": 1, "owner": "Administrator",
"route": "address", "published": 1,
"show_sidebar": 0, "route": "address",
"sidebar_items": [], "route_to_success_link": 0,
"success_url": "/addresses", "show_attachments": 0,
"title": "Address", "show_in_grid": 0,
"show_sidebar": 0,
"sidebar_items": [],
"success_url": "/addresses",
"title": "Address",
"web_form_fields": [ "web_form_fields": [
{ {
"description": "", "allow_read_on_all_link_options": 0,
"fieldname": "address_title", "description": "",
"fieldtype": "Data", "fieldname": "address_title",
"hidden": 0, "fieldtype": "Data",
"label": "Address Title", "hidden": 0,
"max_length": 0, "label": "Address Title",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "address_type", "allow_read_on_all_link_options": 0,
"fieldtype": "Select", "fieldname": "address_type",
"hidden": 0, "fieldtype": "Select",
"label": "Address Type", "hidden": 0,
"max_length": 0, "label": "Address Type",
"max_value": 0, "max_length": 0,
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther", "max_value": 0,
"read_only": 0, "options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther",
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldname": "address_line1", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "address_line1",
"hidden": 0, "fieldtype": "Data",
"label": "Address Line 1", "hidden": 0,
"max_length": 0, "label": "Address Line 1",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldname": "address_line2", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "address_line2",
"hidden": 0, "fieldtype": "Data",
"label": "Address Line 2", "hidden": 0,
"max_length": 0, "label": "Address Line 2",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "city", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "city",
"hidden": 0, "fieldtype": "Data",
"label": "City/Town", "hidden": 0,
"max_length": 0, "label": "City/Town",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldname": "state", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "state",
"hidden": 0, "fieldtype": "Data",
"label": "State", "hidden": 0,
"max_length": 0, "label": "State",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "pincode", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "pincode",
"hidden": 0, "fieldtype": "Data",
"label": "Postal Code", "hidden": 0,
"max_length": 0, "label": "Postal Code",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "country", "allow_read_on_all_link_options": 1,
"fieldtype": "Link", "fieldname": "country",
"hidden": 0, "fieldtype": "Link",
"label": "Country", "hidden": 0,
"max_length": 0, "label": "Country",
"max_value": 0, "max_length": 0,
"options": "Country", "max_value": 0,
"read_only": 0, "options": "Country",
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldtype": "Column Break", "allow_read_on_all_link_options": 0,
"hidden": 0, "fieldtype": "Column Break",
"max_length": 0, "hidden": 0,
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "email_id", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "email_id",
"hidden": 0, "fieldtype": "Data",
"label": "Email Address", "hidden": 0,
"max_length": 0, "label": "Email Address",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "phone", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "phone",
"hidden": 0, "fieldtype": "Data",
"label": "Phone", "hidden": 0,
"max_length": 0, "label": "Phone",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"default": "0", "allow_read_on_all_link_options": 0,
"description": "", "default": "0",
"fieldname": "is_primary_address", "description": "",
"fieldtype": "Check", "fieldname": "is_primary_address",
"hidden": 0, "fieldtype": "Check",
"label": "Preferred Billing Address", "hidden": 0,
"max_length": 0, "label": "Preferred Billing Address",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"default": "0", "allow_read_on_all_link_options": 0,
"description": "", "default": "0",
"fieldname": "is_shipping_address", "description": "",
"fieldtype": "Check", "fieldname": "is_shipping_address",
"hidden": 0, "fieldtype": "Check",
"label": "Preferred Shipping Address", "hidden": 0,
"max_length": 0, "label": "Preferred Shipping Address",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
"reqd": 0,
"show_in_filter": 0
} }
] ]
} }