Merge branch 'develop' of https://github.com/frappe/erpnext into develop
This commit is contained in:
commit
56819d9389
@ -389,8 +389,7 @@
|
|||||||
"fieldname": "rate_or_discount",
|
"fieldname": "rate_or_discount",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Rate or Discount",
|
"label": "Rate or Discount",
|
||||||
"options": "\nRate\nDiscount Percentage\nDiscount Amount",
|
"options": "\nRate\nDiscount Percentage\nDiscount Amount"
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Grand Total",
|
"default": "Grand Total",
|
||||||
@ -439,19 +438,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"depends_on": "eval:!doc.mixed_conditions",
|
"depends_on": "eval:!doc.mixed_conditions && doc.apply_on != 'Transaction'",
|
||||||
"fieldname": "same_item",
|
"fieldname": "same_item",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Same Item"
|
"label": "Same Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.same_item || doc.mixed_conditions",
|
"depends_on": "eval:(!doc.same_item || doc.apply_on == 'Transaction') || doc.mixed_conditions",
|
||||||
"fieldname": "free_item",
|
"fieldname": "free_item",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Free Item",
|
"label": "Free Item",
|
||||||
"options": "Item"
|
"options": "Item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "free_qty",
|
"fieldname": "free_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Qty"
|
"label": "Qty"
|
||||||
@ -554,7 +554,7 @@
|
|||||||
],
|
],
|
||||||
"icon": "fa fa-gift",
|
"icon": "fa fa-gift",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"modified": "2019-10-15 12:39:40.399792",
|
"modified": "2019-12-18 17:29:22.957077",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Pricing Rule",
|
"name": "Pricing Rule",
|
||||||
|
@ -47,6 +47,9 @@ class PricingRule(Document):
|
|||||||
if tocheck and not self.get(tocheck):
|
if tocheck and not self.get(tocheck):
|
||||||
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
|
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
|
||||||
|
|
||||||
|
if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
|
||||||
|
throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
|
||||||
|
|
||||||
def validate_applicable_for_selling_or_buying(self):
|
def validate_applicable_for_selling_or_buying(self):
|
||||||
if not self.selling and not self.buying:
|
if not self.selling and not self.buying:
|
||||||
throw(_("Atleast one of the Selling or Buying must be selected"))
|
throw(_("Atleast one of the Selling or Buying must be selected"))
|
||||||
@ -182,7 +185,7 @@ def get_serial_no_for_item(args):
|
|||||||
|
|
||||||
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
|
def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
|
||||||
from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules,
|
from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules,
|
||||||
get_applied_pricing_rules, get_pricing_rule_items)
|
get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule)
|
||||||
|
|
||||||
if isinstance(doc, string_types):
|
if isinstance(doc, string_types):
|
||||||
doc = json.loads(doc)
|
doc = json.loads(doc)
|
||||||
@ -241,9 +244,11 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
|||||||
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
|
if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
|
||||||
return item_details
|
return item_details
|
||||||
|
|
||||||
if (not pricing_rule.validate_applied_rule and
|
if not pricing_rule.validate_applied_rule:
|
||||||
pricing_rule.price_or_product_discount == "Price"):
|
if pricing_rule.price_or_product_discount == "Price":
|
||||||
apply_price_discount_pricing_rule(pricing_rule, item_details, args)
|
apply_price_discount_rule(pricing_rule, item_details, args)
|
||||||
|
else:
|
||||||
|
get_product_discount_rule(pricing_rule, item_details, doc)
|
||||||
|
|
||||||
item_details.has_pricing_rule = 1
|
item_details.has_pricing_rule = 1
|
||||||
|
|
||||||
@ -293,7 +298,7 @@ def get_pricing_rule_details(args, pricing_rule):
|
|||||||
'child_docname': args.get('child_docname')
|
'child_docname': args.get('child_docname')
|
||||||
})
|
})
|
||||||
|
|
||||||
def apply_price_discount_pricing_rule(pricing_rule, item_details, args):
|
def apply_price_discount_rule(pricing_rule, item_details, args):
|
||||||
item_details.pricing_rule_for = pricing_rule.rate_or_discount
|
item_details.pricing_rule_for = pricing_rule.rate_or_discount
|
||||||
|
|
||||||
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
|
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
|
||||||
|
@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe, copy, json
|
import frappe, copy, json
|
||||||
from frappe import throw, _
|
from frappe import throw, _
|
||||||
from six import string_types
|
from six import string_types
|
||||||
from frappe.utils import flt, cint, get_datetime
|
from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
|
||||||
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor
|
from erpnext.stock.get_item_details import get_conversion_factor
|
||||||
@ -284,7 +284,7 @@ def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None):
|
|||||||
status = True
|
status = True
|
||||||
|
|
||||||
# if user has created item price against the transaction UOM
|
# if user has created item price against the transaction UOM
|
||||||
if rule.get("uom") == args.get("uom"):
|
if args and rule.get("uom") == args.get("uom"):
|
||||||
conversion_factor = 1.0
|
conversion_factor = 1.0
|
||||||
|
|
||||||
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
|
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
|
||||||
@ -408,7 +408,8 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
conditions = get_other_conditions(conditions, values, doc)
|
conditions = get_other_conditions(conditions, values, doc)
|
||||||
|
|
||||||
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
|
||||||
where {conditions} """.format(conditions = conditions), values, as_dict=1)
|
where {conditions} and `tabPricing Rule`.disable = 0
|
||||||
|
""".format(conditions = conditions), values, as_dict=1)
|
||||||
|
|
||||||
if pricing_rules:
|
if pricing_rules:
|
||||||
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
|
||||||
@ -420,39 +421,65 @@ def apply_pricing_rule_on_transaction(doc):
|
|||||||
doc.set('apply_discount_on', d.apply_discount_on)
|
doc.set('apply_discount_on', d.apply_discount_on)
|
||||||
|
|
||||||
for field in ['additional_discount_percentage', 'discount_amount']:
|
for field in ['additional_discount_percentage', 'discount_amount']:
|
||||||
if not d.get(field): continue
|
|
||||||
|
|
||||||
pr_field = ('discount_percentage'
|
pr_field = ('discount_percentage'
|
||||||
if field == 'additional_discount_percentage' else field)
|
if field == 'additional_discount_percentage' else field)
|
||||||
|
|
||||||
|
if not d.get(pr_field): continue
|
||||||
|
|
||||||
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
|
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
|
||||||
frappe.msgprint(_("User has not applied rule on the invoice {0}")
|
frappe.msgprint(_("User has not applied rule on the invoice {0}")
|
||||||
.format(doc.name))
|
.format(doc.name))
|
||||||
else:
|
else:
|
||||||
doc.set(field, d.get(pr_field))
|
doc.set(field, d.get(pr_field))
|
||||||
|
|
||||||
|
doc.calculate_taxes_and_totals()
|
||||||
elif d.price_or_product_discount == 'Product':
|
elif d.price_or_product_discount == 'Product':
|
||||||
apply_pricing_rule_for_free_items(doc, d)
|
item_details = frappe._dict({'parenttype': doc.doctype})
|
||||||
|
get_product_discount_rule(d, item_details, doc)
|
||||||
|
apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
|
||||||
|
doc.set_missing_values()
|
||||||
|
|
||||||
def get_applied_pricing_rules(item_row):
|
def get_applied_pricing_rules(item_row):
|
||||||
return (item_row.get("pricing_rules").split(',')
|
return (item_row.get("pricing_rules").split(',')
|
||||||
if item_row.get("pricing_rules") else [])
|
if item_row.get("pricing_rules") else [])
|
||||||
|
|
||||||
def apply_pricing_rule_for_free_items(doc, pricing_rule):
|
def get_product_discount_rule(pricing_rule, item_details, doc=None):
|
||||||
if pricing_rule.get('free_item'):
|
free_item = (pricing_rule.free_item
|
||||||
|
if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code)
|
||||||
|
|
||||||
|
if not free_item:
|
||||||
|
frappe.throw(_("Free item not set in the pricing rule {0}")
|
||||||
|
.format(get_link_to_form("Pricing Rule", pricing_rule.name)))
|
||||||
|
|
||||||
|
item_details.free_item_data = {
|
||||||
|
'item_code': free_item,
|
||||||
|
'qty': pricing_rule.free_qty or 1,
|
||||||
|
'rate': pricing_rule.free_item_rate or 0,
|
||||||
|
'price_list_rate': pricing_rule.free_item_rate or 0,
|
||||||
|
'is_free_item': 1
|
||||||
|
}
|
||||||
|
|
||||||
|
item_data = frappe.get_cached_value('Item', free_item, ['item_name',
|
||||||
|
'description', 'stock_uom'], as_dict=1)
|
||||||
|
|
||||||
|
item_details.free_item_data.update(item_data)
|
||||||
|
item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
|
||||||
|
item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
|
||||||
|
item_details.free_item_data['uom']).get("conversion_factor", 1)
|
||||||
|
|
||||||
|
if item_details.get("parenttype") == 'Purchase Order':
|
||||||
|
item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()
|
||||||
|
|
||||||
|
if item_details.get("parenttype") == 'Sales Order':
|
||||||
|
item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
|
||||||
|
|
||||||
|
def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
|
||||||
|
if pricing_rule_args.get('item_code'):
|
||||||
items = [d.item_code for d in doc.items
|
items = [d.item_code for d in doc.items
|
||||||
if d.item_code == (d.item_code
|
if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item]
|
||||||
if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item]
|
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
doc.append('items', {
|
doc.append('items', pricing_rule_args)
|
||||||
'item_code': pricing_rule.get('free_item'),
|
|
||||||
'qty': pricing_rule.get('free_qty'),
|
|
||||||
'uom': pricing_rule.get('free_item_uom'),
|
|
||||||
'rate': pricing_rule.get('free_item_rate') or 0,
|
|
||||||
'is_free_item': 1
|
|
||||||
})
|
|
||||||
|
|
||||||
doc.set_missing_values()
|
|
||||||
|
|
||||||
def get_pricing_rule_items(pr_doc):
|
def get_pricing_rule_items(pr_doc):
|
||||||
apply_on_data = []
|
apply_on_data = []
|
||||||
|
@ -382,7 +382,6 @@ cur_frm.fields_dict['items'].grid.get_field("item_code").get_query = function(do
|
|||||||
|
|
||||||
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
||||||
// filter on Account
|
// filter on Account
|
||||||
if (doc.supplier) {
|
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
'account_type': 'Payable',
|
'account_type': 'Payable',
|
||||||
@ -390,15 +389,6 @@ cur_frm.fields_dict['credit_to'].get_query = function(doc) {
|
|||||||
'company': doc.company
|
'company': doc.company
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
'report_type': 'Balance Sheet',
|
|
||||||
'is_group': 0,
|
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Print Heading
|
// Get Print Heading
|
||||||
|
@ -556,8 +556,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.set_query("debit_to", function(doc) {
|
cur_frm.set_query("debit_to", function(doc) {
|
||||||
// filter on Account
|
|
||||||
if (doc.customer) {
|
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
'account_type': 'Receivable',
|
'account_type': 'Receivable',
|
||||||
@ -565,15 +563,6 @@ cur_frm.set_query("debit_to", function(doc) {
|
|||||||
'company': doc.company
|
'company': doc.company
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
filters: {
|
|
||||||
'report_type': 'Balance Sheet',
|
|
||||||
'is_group': 0,
|
|
||||||
'company': doc.company
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
|
cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
|
||||||
|
@ -188,7 +188,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-11-07 13:31:17.999744",
|
"modified": "2019-12-20 14:48:01.990600",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Share Transfer",
|
"name": "Share Transfer",
|
||||||
@ -196,6 +196,7 @@
|
|||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
@ -221,6 +222,7 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
@ -230,6 +232,7 @@
|
|||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Accounts Manager",
|
"role": "Accounts Manager",
|
||||||
"share": 1,
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -90,8 +90,12 @@ def merge_similar_entries(gl_map):
|
|||||||
else:
|
else:
|
||||||
merged_gl_map.append(entry)
|
merged_gl_map.append(entry)
|
||||||
|
|
||||||
|
company = gl_map[0].company if gl_map else erpnext.get_default_company()
|
||||||
|
company_currency = erpnext.get_company_currency(company)
|
||||||
|
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
|
||||||
|
|
||||||
# filter zero debit and credit entries
|
# filter zero debit and credit entries
|
||||||
merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map)
|
merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
|
||||||
merged_gl_map = list(merged_gl_map)
|
merged_gl_map = list(merged_gl_map)
|
||||||
|
|
||||||
return merged_gl_map
|
return merged_gl_map
|
||||||
|
@ -171,7 +171,7 @@ class ReceivablePayableReport(object):
|
|||||||
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
|
||||||
row.invoice_grand_total = row.invoiced
|
row.invoice_grand_total = row.invoiced
|
||||||
|
|
||||||
if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
|
if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
|
||||||
# non-zero oustanding, we must consider this row
|
# non-zero oustanding, we must consider this row
|
||||||
|
|
||||||
if self.is_invoice(row) and self.filters.based_on_payment_terms:
|
if self.is_invoice(row) and self.filters.based_on_payment_terms:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{%
|
{%
|
||||||
var report_columns = report.get_columns_for_print();
|
var report_columns = report.get_columns_for_print();
|
||||||
|
report_columns = report_columns.filter(col => !col.hidden);
|
||||||
|
|
||||||
if (report_columns.length > 8) {
|
if (report_columns.length > 8) {
|
||||||
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
|
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
|
||||||
@ -15,34 +16,35 @@
|
|||||||
height: 37px;
|
height: 37px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) %}
|
|
||||||
{% if(letterhead) { %}
|
|
||||||
<div style="margin-bottom: 7px;" class="text-center">
|
|
||||||
{%= frappe.boot.letter_heads[letterhead].header %}
|
|
||||||
</div>
|
|
||||||
{% } %}
|
|
||||||
<h2 class="text-center">{%= __(report.report_name) %}</h2>
|
<h2 class="text-center">{%= __(report.report_name) %}</h2>
|
||||||
<h3 class="text-center">{%= filters.company %}</h3>
|
<h3 class="text-center">{%= filters.company %}</h3>
|
||||||
|
|
||||||
{% if 'cost_center' in filters %}
|
{% if 'cost_center' in filters %}
|
||||||
<h3 class="text-center">{%= filters.cost_center %}</h3>
|
<h3 class="text-center">{%= filters.cost_center %}</h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h3 class="text-center">{%= filters.fiscal_year %}</h3>
|
<h3 class="text-center">{%= filters.fiscal_year %}</h3>
|
||||||
<h5 class="text-center">{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %} </h4>
|
<h5 class="text-center">
|
||||||
|
{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
|
||||||
|
</h5>
|
||||||
{% if (filters.from_date) { %}
|
{% if (filters.from_date) { %}
|
||||||
<h4 class="text-center">{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}</h3>
|
<h5 class="text-center">
|
||||||
|
{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}
|
||||||
|
</h5>
|
||||||
{% } %}
|
{% } %}
|
||||||
<hr>
|
<hr>
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: {%= 100 - (report_columns.length - 2) * 13 %}%"></th>
|
<th style="width: {%= 100 - (report_columns.length - 1) * 13 %}%"></th>
|
||||||
{% for(var i=2, l=report_columns.length; i<l; i++) { %}
|
{% for (let i=1, l=report_columns.length; i<l; i++) { %}
|
||||||
<th class="text-right">{%= report_columns[i].label %}</th>
|
<th class="text-right">{%= report_columns[i].label %}</th>
|
||||||
{% } %}
|
{% } %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for(var j=0, k=data.length-1; j<k; j++) { %}
|
{% for(let j=0, k=data.length-1; j<k; j++) { %}
|
||||||
{%
|
{%
|
||||||
var row = data[j];
|
var row = data[j];
|
||||||
var row_class = data[j].parent_account ? "" : "financial-statements-important";
|
var row_class = data[j].parent_account ? "" : "financial-statements-important";
|
||||||
@ -52,11 +54,11 @@
|
|||||||
<td>
|
<td>
|
||||||
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
|
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
|
||||||
</td>
|
</td>
|
||||||
{% for(var i=2, l=report_columns.length; i<l; i++) { %}
|
{% for(let i=1, l=report_columns.length; i<l; i++) { %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
{% var fieldname = report_columns[i].fieldname; %}
|
{% const fieldname = report_columns[i].fieldname; %}
|
||||||
{% if (!is_null(row[fieldname])) { %}
|
{% if (!is_null(row[fieldname])) { %}
|
||||||
{%= format_currency(row[fieldname], filters.presentation_currency) %}
|
{%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
|
||||||
{% } %}
|
{% } %}
|
||||||
</td>
|
</td>
|
||||||
{% } %}
|
{% } %}
|
||||||
@ -64,4 +66,6 @@
|
|||||||
{% } %}
|
{% } %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
|
<p class="text-right text-muted">
|
||||||
|
Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
|
||||||
|
</p>
|
||||||
|
@ -264,8 +264,8 @@ def filter_out_zero_value_rows(data, parent_children_map, show_zero_values=False
|
|||||||
|
|
||||||
def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
|
def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
|
||||||
total_row = {
|
total_row = {
|
||||||
"account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
"account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||||
"account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
|
"account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
|
||||||
"currency": company_currency
|
"currency": company_currency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,32 +38,46 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
|
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
|
||||||
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
|
||||||
|
|
||||||
row = [
|
row = {
|
||||||
inv.name, inv.posting_date, inv.customer, inv.customer_name
|
'invoice': inv.name,
|
||||||
]
|
'posting_date': inv.posting_date,
|
||||||
|
'customer': inv.customer,
|
||||||
|
'customer_name': inv.customer_name
|
||||||
|
}
|
||||||
|
|
||||||
if additional_query_columns:
|
if additional_query_columns:
|
||||||
for col in additional_query_columns:
|
for col in additional_query_columns:
|
||||||
row.append(inv.get(col))
|
row.update({
|
||||||
|
col: inv.get(col)
|
||||||
|
})
|
||||||
|
|
||||||
|
row.update({
|
||||||
|
'customer_group': inv.get("customer_group"),
|
||||||
|
'territory': inv.get("territory"),
|
||||||
|
'tax_id': inv.get("tax_id"),
|
||||||
|
'receivable_account': inv.debit_to,
|
||||||
|
'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])),
|
||||||
|
'project': inv.project,
|
||||||
|
'owner': inv.owner,
|
||||||
|
'remarks': inv.remarks,
|
||||||
|
'sales_order': ", ".join(sales_order),
|
||||||
|
'delivery_note': ", ".join(delivery_note),
|
||||||
|
'cost_center': ", ".join(cost_center),
|
||||||
|
'warehouse': ", ".join(warehouse),
|
||||||
|
'currency': company_currency
|
||||||
|
})
|
||||||
|
|
||||||
row +=[
|
|
||||||
inv.get("customer_group"),
|
|
||||||
inv.get("territory"),
|
|
||||||
inv.get("tax_id"),
|
|
||||||
inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
|
|
||||||
inv.project, inv.owner, inv.remarks,
|
|
||||||
", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center),
|
|
||||||
", ".join(warehouse), company_currency
|
|
||||||
]
|
|
||||||
# map income values
|
# map income values
|
||||||
base_net_total = 0
|
base_net_total = 0
|
||||||
for income_acc in income_accounts:
|
for income_acc in income_accounts:
|
||||||
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
|
||||||
base_net_total += income_amount
|
base_net_total += income_amount
|
||||||
row.append(income_amount)
|
row.update({
|
||||||
|
frappe.scrub(income_acc): income_amount
|
||||||
|
})
|
||||||
|
|
||||||
# net total
|
# net total
|
||||||
row.append(base_net_total or inv.base_net_total)
|
row.update({'net_total': base_net_total or inv.base_net_total})
|
||||||
|
|
||||||
# tax account
|
# tax account
|
||||||
total_tax = 0
|
total_tax = 0
|
||||||
@ -72,10 +86,18 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
|
||||||
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
|
||||||
total_tax += tax_amount
|
total_tax += tax_amount
|
||||||
row.append(tax_amount)
|
row.update({
|
||||||
|
frappe.scrub(tax_acc): tax_amount
|
||||||
|
})
|
||||||
|
|
||||||
# total tax, grand total, outstanding amount & rounded total
|
# total tax, grand total, outstanding amount & rounded total
|
||||||
row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount]
|
|
||||||
|
row.update({
|
||||||
|
'tax_total': total_tax,
|
||||||
|
'grand_total': inv.base_grand_total,
|
||||||
|
'rounded_total': inv.base_rounded_total,
|
||||||
|
'outstanding_amount': inv.outstanding_amount
|
||||||
|
})
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
@ -84,19 +106,118 @@ def _execute(filters, additional_table_columns=None, additional_query_columns=No
|
|||||||
def get_columns(invoice_list, additional_table_columns):
|
def get_columns(invoice_list, additional_table_columns):
|
||||||
"""return columns based on filters"""
|
"""return columns based on filters"""
|
||||||
columns = [
|
columns = [
|
||||||
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
|
{
|
||||||
_("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
|
'label': _("Invoice"),
|
||||||
|
'fieldname': 'invoice',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Invoice',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Posting Date"),
|
||||||
|
'fieldname': 'posting_date',
|
||||||
|
'fieldtype': 'Date',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Customer"),
|
||||||
|
'fieldname': 'customer',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Customer',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Customer Name"),
|
||||||
|
'fieldname': 'customer_name',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if additional_table_columns:
|
if additional_table_columns:
|
||||||
columns += additional_table_columns
|
columns += additional_table_columns
|
||||||
|
|
||||||
columns +=[
|
columns +=[
|
||||||
_("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
|
{
|
||||||
_("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
|
'label': _("Custmer Group"),
|
||||||
_("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
|
'fieldname': 'customer_group',
|
||||||
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
|
'fieldtype': 'Link',
|
||||||
_("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
|
'options': 'Customer Group',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Territory"),
|
||||||
|
'fieldname': 'territory',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Territory',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Tax Id"),
|
||||||
|
'fieldname': 'tax_id',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Receivable Account"),
|
||||||
|
'fieldname': 'receivable_account',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Account',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Mode Of Payment"),
|
||||||
|
'fieldname': 'mode_of_payment',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Project"),
|
||||||
|
'fieldname': 'project',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'project',
|
||||||
|
'width': 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Owner"),
|
||||||
|
'fieldname': 'owner',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Remarks"),
|
||||||
|
'fieldname': 'remarks',
|
||||||
|
'fieldtype': 'Data',
|
||||||
|
'width': 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Sales Order"),
|
||||||
|
'fieldname': 'sales_order',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Sales Order',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Delivery Note"),
|
||||||
|
'fieldname': 'delivery_note',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Delivery Note',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Cost Center"),
|
||||||
|
'fieldname': 'cost_center',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Cost Center',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'label': _("Warehouse"),
|
||||||
|
'fieldname': 'warehouse',
|
||||||
|
'fieldtype': 'Link',
|
||||||
|
'options': 'Warehouse',
|
||||||
|
'width': 100
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"label": _("Currency"),
|
"label": _("Currency"),
|
||||||
@ -105,7 +226,10 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
income_accounts = tax_accounts = income_columns = tax_columns = []
|
income_accounts = []
|
||||||
|
tax_accounts = []
|
||||||
|
income_columns = []
|
||||||
|
tax_columns = []
|
||||||
|
|
||||||
if invoice_list:
|
if invoice_list:
|
||||||
income_accounts = frappe.db.sql_list("""select distinct income_account
|
income_accounts = frappe.db.sql_list("""select distinct income_account
|
||||||
@ -119,14 +243,65 @@ def get_columns(invoice_list, additional_table_columns):
|
|||||||
and parent in (%s) order by account_head""" %
|
and parent in (%s) order by account_head""" %
|
||||||
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
|
||||||
|
|
||||||
income_columns = [(account + ":Currency/currency:120") for account in income_accounts]
|
for account in income_accounts:
|
||||||
|
income_columns.append({
|
||||||
|
"label": account,
|
||||||
|
"fieldname": frappe.scrub(account),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
})
|
||||||
|
|
||||||
for account in tax_accounts:
|
for account in tax_accounts:
|
||||||
if account not in income_accounts:
|
if account not in income_accounts:
|
||||||
tax_columns.append(account + ":Currency/currency:120")
|
tax_columns.append({
|
||||||
|
"label": account,
|
||||||
|
"fieldname": frappe.scrub(account),
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
})
|
||||||
|
|
||||||
columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
|
net_total_column = [{
|
||||||
[_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
|
"label": _("Net Total"),
|
||||||
_("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
|
"fieldname": "net_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
}]
|
||||||
|
|
||||||
|
total_columns = [
|
||||||
|
{
|
||||||
|
"label": _("Tax Total"),
|
||||||
|
"fieldname": "tax_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Grand Total"),
|
||||||
|
"fieldname": "grand_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Rounded Total"),
|
||||||
|
"fieldname": "rounded_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Outstanding Amount"),
|
||||||
|
"fieldname": "outstanding_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": 'currency',
|
||||||
|
"width": 120
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
columns = columns + income_columns + net_total_column + tax_columns + total_columns
|
||||||
|
|
||||||
return columns, income_accounts, tax_accounts
|
return columns, income_accounts, tax_accounts
|
||||||
|
|
||||||
|
@ -144,6 +144,10 @@ frappe.ui.form.on('Asset', {
|
|||||||
frm.set_df_property('purchase_invoice', 'read_only', 1);
|
frm.set_df_property('purchase_invoice', 'read_only', 1);
|
||||||
frm.set_df_property('purchase_receipt', 'read_only', 1);
|
frm.set_df_property('purchase_receipt', 'read_only', 1);
|
||||||
}
|
}
|
||||||
|
else if (frm.doc.is_existing_asset) {
|
||||||
|
frm.toggle_reqd('purchase_receipt', 0);
|
||||||
|
frm.toggle_reqd('purchase_invoice', 0);
|
||||||
|
}
|
||||||
else if (frm.doc.purchase_receipt) {
|
else if (frm.doc.purchase_receipt) {
|
||||||
// if purchase receipt link is set then set PI disabled
|
// if purchase receipt link is set then set PI disabled
|
||||||
frm.toggle_reqd('purchase_invoice', 0);
|
frm.toggle_reqd('purchase_invoice', 0);
|
||||||
@ -256,6 +260,7 @@ frappe.ui.form.on('Asset', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
is_existing_asset: function(frm) {
|
is_existing_asset: function(frm) {
|
||||||
|
frm.trigger("toggle_reference_doc");
|
||||||
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
|
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_src": "/assets/erpnext/images/illustrations/supplier-onboard.png",
|
"image_src": "",
|
||||||
|
"is_completed": 0,
|
||||||
"max_count": 3,
|
"max_count": 3,
|
||||||
"modified": "2019-12-03 22:53:50.552445",
|
"modified": "2019-12-09 17:54:18.452038",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Add A Few Suppliers",
|
"name": "Add A Few Suppliers",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
@ -319,8 +319,8 @@ class AccountsController(TransactionBase):
|
|||||||
if item.get('discount_amount'):
|
if item.get('discount_amount'):
|
||||||
item.rate = item.price_list_rate - item.discount_amount
|
item.rate = item.price_list_rate - item.discount_amount
|
||||||
|
|
||||||
elif pricing_rule_args.get('free_item'):
|
elif pricing_rule_args.get('free_item_data'):
|
||||||
apply_pricing_rule_for_free_items(self, pricing_rule_args)
|
apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
|
||||||
|
|
||||||
elif pricing_rule_args.get("validate_applied_rule"):
|
elif pricing_rule_args.get("validate_applied_rule"):
|
||||||
for pricing_rule in get_applied_pricing_rules(item):
|
for pricing_rule in get_applied_pricing_rules(item):
|
||||||
|
@ -265,16 +265,17 @@ class BuyingController(StockController):
|
|||||||
|
|
||||||
fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
|
fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
|
||||||
|
|
||||||
raw_material_data = backflushed_raw_materials_map.get(item_key, {})
|
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
|
||||||
|
backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
|
||||||
|
|
||||||
|
for raw_material in transferred_raw_materials + non_stock_items:
|
||||||
|
rm_item_key = '{}{}'.format(raw_material.rm_item_code, item.purchase_order)
|
||||||
|
raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
|
||||||
|
|
||||||
consumed_qty = raw_material_data.get('qty', 0)
|
consumed_qty = raw_material_data.get('qty', 0)
|
||||||
consumed_serial_nos = raw_material_data.get('serial_nos', '')
|
consumed_serial_nos = raw_material_data.get('serial_nos', '')
|
||||||
consumed_batch_nos = raw_material_data.get('batch_nos', '')
|
consumed_batch_nos = raw_material_data.get('batch_nos', '')
|
||||||
|
|
||||||
transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
|
|
||||||
backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
|
|
||||||
|
|
||||||
for raw_material in transferred_raw_materials + non_stock_items:
|
|
||||||
transferred_qty = raw_material.qty
|
transferred_qty = raw_material.qty
|
||||||
|
|
||||||
rm_qty_to_be_consumed = transferred_qty - consumed_qty
|
rm_qty_to_be_consumed = transferred_qty - consumed_qty
|
||||||
|
@ -180,6 +180,7 @@ standard_portal_menu_items = [
|
|||||||
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"},
|
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"},
|
||||||
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"},
|
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"},
|
||||||
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
|
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
|
||||||
|
{"title": _("Appointment Booking"), "route": "/book_appointment"},
|
||||||
]
|
]
|
||||||
|
|
||||||
default_roles = [
|
default_roles = [
|
||||||
|
@ -1,9 +1,44 @@
|
|||||||
<h3>{{_("Training Event")}}</h3>
|
<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||||
|
<tr height="10"></tr>
|
||||||
|
<tr>
|
||||||
|
<td width="15"></td>
|
||||||
|
<td>
|
||||||
|
<div class="text-medium text-muted">
|
||||||
|
<span>{{_("Training Event:")}} {{ doc.event_name }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="15"></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="10"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<p>{{ doc.introduction }}</p>
|
<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||||
|
<tr height="10"></tr>
|
||||||
<h4>{{_("Details")}}</h4>
|
<tr>
|
||||||
{{_("Event Name")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
|
<td width="15"></td>
|
||||||
<br>{{_("Event Location")}}: {{ doc.location }}
|
<td>
|
||||||
<br>{{_("Start Time")}}: {{ doc.start_time }}
|
<div>
|
||||||
<br>{{_("End Time")}}: {{ doc.end_time }}
|
{{ doc.introduction }}
|
||||||
|
<ul class="list-unstyled" style="line-height: 1.7">
|
||||||
|
<li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
|
||||||
|
{% set start = frappe.utils.get_datetime(doc.start_time) %}
|
||||||
|
{% set end = frappe.utils.get_datetime(doc.end_time) %}
|
||||||
|
{% if start.date() == end.date() %}
|
||||||
|
<li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
|
||||||
|
<li>
|
||||||
|
{{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
<li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="15"></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="10"></tr>
|
||||||
|
</table>
|
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"attach_print": 0,
|
"attach_print": 0,
|
||||||
|
"channel": "Email",
|
||||||
|
"condition": "",
|
||||||
"creation": "2017-08-11 03:13:40.519614",
|
"creation": "2017-08-11 03:13:40.519614",
|
||||||
"days_in_advance": 0,
|
"days_in_advance": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
@ -9,8 +11,8 @@
|
|||||||
"event": "Submit",
|
"event": "Submit",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"message": "<h3>{{_(\"Training Event\")}}</h3>\n\n<p>{{ doc.introduction }}</p>\n\n<h4>{{_(\"Details\")}}</h4>\n{{_(\"Event Name\")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n<br>{{_(\"Event Location\")}}: {{ doc.location }}\n<br>{{_(\"Start Time\")}}: {{ doc.start_time }}\n<br>{{_(\"End Time\")}}: {{ doc.end_time }}\n",
|
"message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div class=\"text-medium text-muted\">\n <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div>\n <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n <li>{{ doc.introduction }}</li>\n <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n <li>\n {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n </li>\n {% else %}\n <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n {% endif %}\n </ul>\n {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>",
|
||||||
"modified": "2017-08-13 22:49:42.338881",
|
"modified": "2019-11-29 15:38:31.805409",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Training Scheduled",
|
"name": "Training Scheduled",
|
||||||
|
@ -1,9 +1,44 @@
|
|||||||
<h3>{{_("Training Event")}}</h3>
|
<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||||
<p>{{ message }}</p>
|
<tr height="10"></tr>
|
||||||
|
<tr>
|
||||||
|
<td width="15"></td>
|
||||||
|
<td>
|
||||||
|
<div class="text-medium text-muted">
|
||||||
|
<span>{{_("Training Event:")}} {{ doc.event_name }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="15"></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="10"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<h4>{{_("Details")}}</h4>
|
<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||||
{{_("Event Name")}}: <a href="{{ event_link }}">{{ name }}</a>
|
<tr height="10"></tr>
|
||||||
<br>{{_("Event Location")}}: {{ location }}
|
<tr>
|
||||||
<br>{{_("Start Time")}}: {{ start_time }}
|
<td width="15"></td>
|
||||||
<br>{{_("End Time")}}: {{ end_time }}
|
<td>
|
||||||
<br>{{_("Attendance")}}: {{ attendance }}
|
<div>
|
||||||
|
{{ doc.introduction }}
|
||||||
|
<ul class="list-unstyled" style="line-height: 1.7">
|
||||||
|
<li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
|
||||||
|
{% set start = frappe.utils.get_datetime(doc.start_time) %}
|
||||||
|
{% set end = frappe.utils.get_datetime(doc.end_time) %}
|
||||||
|
{% if start.date() == end.date() %}
|
||||||
|
<li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
|
||||||
|
<li>
|
||||||
|
{{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
<li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="15"></td>
|
||||||
|
</tr>
|
||||||
|
<tr height="10"></tr>
|
||||||
|
</table>
|
@ -65,6 +65,7 @@ class BOM(WebsiteGenerator):
|
|||||||
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
|
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
|
frappe.cache().hdel('bom_children', self.name)
|
||||||
self.check_recursion()
|
self.check_recursion()
|
||||||
self.update_stock_qty()
|
self.update_stock_qty()
|
||||||
self.update_exploded_items()
|
self.update_exploded_items()
|
||||||
|
@ -605,6 +605,8 @@ erpnext.work_order = {
|
|||||||
description: __('Max: {0}', [max]),
|
description: __('Max: {0}', [max]),
|
||||||
default: max
|
default: max
|
||||||
}, data => {
|
}, data => {
|
||||||
|
max += (max * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100;
|
||||||
|
|
||||||
if (data.qty > max) {
|
if (data.qty > max) {
|
||||||
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
|
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
|
||||||
reject();
|
reject();
|
||||||
|
@ -38,7 +38,7 @@ class WorkOrder(Document):
|
|||||||
ms = frappe.get_doc("Manufacturing Settings")
|
ms = frappe.get_doc("Manufacturing Settings")
|
||||||
self.set_onload("material_consumption", ms.material_consumption)
|
self.set_onload("material_consumption", ms.material_consumption)
|
||||||
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
|
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
|
||||||
|
self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_production_item()
|
self.validate_production_item()
|
||||||
@ -657,8 +657,9 @@ def make_work_order(item, qty=0, project=None):
|
|||||||
wo_doc = frappe.new_doc("Work Order")
|
wo_doc = frappe.new_doc("Work Order")
|
||||||
wo_doc.production_item = item
|
wo_doc.production_item = item
|
||||||
wo_doc.update(item_details)
|
wo_doc.update(item_details)
|
||||||
if qty > 0:
|
|
||||||
wo_doc.qty = qty
|
if flt(qty) > 0:
|
||||||
|
wo_doc.qty = flt(qty)
|
||||||
wo_doc.get_items_and_operations_from_bom()
|
wo_doc.get_items_and_operations_from_bom()
|
||||||
|
|
||||||
return wo_doc
|
return wo_doc
|
||||||
|
@ -27,6 +27,8 @@ def execute():
|
|||||||
tax_category = inter_state_category.name
|
tax_category = inter_state_category.name
|
||||||
|
|
||||||
for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'):
|
for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'):
|
||||||
|
if not frappe.get_meta(doctype).has_field('is_inter_state'): continue
|
||||||
|
|
||||||
template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name'])
|
template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name'])
|
||||||
if template:
|
if template:
|
||||||
frappe.db.set_value(doctype, template, 'tax_category', tax_category)
|
frappe.db.set_value(doctype, template, 'tax_category', tax_category)
|
||||||
|
@ -7,6 +7,8 @@ def execute():
|
|||||||
if not company:
|
if not company:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
frappe.reload_doc('accounts', 'doctype', 'Tax Category')
|
||||||
|
|
||||||
make_custom_fields()
|
make_custom_fields()
|
||||||
|
|
||||||
for doctype in ['Sales Invoice', 'Purchase Invoice']:
|
for doctype in ['Sales Invoice', 'Purchase Invoice']:
|
||||||
|
@ -52,7 +52,6 @@ def get_attribute_filter_data():
|
|||||||
|
|
||||||
|
|
||||||
def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
|
def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
|
||||||
|
|
||||||
if attribute_filters:
|
if attribute_filters:
|
||||||
item_codes = get_item_codes_by_attributes(attribute_filters)
|
item_codes = get_item_codes_by_attributes(attribute_filters)
|
||||||
items_by_attributes = get_items([['name', 'in', item_codes]])
|
items_by_attributes = get_items([['name', 'in', item_codes]])
|
||||||
@ -302,6 +301,8 @@ def get_items(filters=None, search=None):
|
|||||||
if isinstance(filters, dict):
|
if isinstance(filters, dict):
|
||||||
filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
|
filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
|
||||||
|
|
||||||
|
enabled_items_filter = get_conditions({ 'disabled': 0 }, 'and')
|
||||||
|
|
||||||
show_in_website_condition = ''
|
show_in_website_condition = ''
|
||||||
if products_settings.hide_variants:
|
if products_settings.hide_variants:
|
||||||
show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
|
show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
|
||||||
@ -337,7 +338,8 @@ def get_items(filters=None, search=None):
|
|||||||
filter_condition = get_conditions(filters, 'and')
|
filter_condition = get_conditions(filters, 'and')
|
||||||
|
|
||||||
where_conditions = ' and '.join(
|
where_conditions = ' and '.join(
|
||||||
[condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition]
|
[condition for condition in [enabled_items_filter, show_in_website_condition, \
|
||||||
|
search_condition, filter_condition] if condition]
|
||||||
)
|
)
|
||||||
|
|
||||||
left_joins = []
|
left_joins = []
|
||||||
|
@ -47,11 +47,11 @@ class Task(NestedSet):
|
|||||||
if not self.project or frappe.flags.in_test:
|
if not self.project or frappe.flags.in_test:
|
||||||
return
|
return
|
||||||
|
|
||||||
expected_end_date = getdate(frappe.db.get_value("Project", self.project, "expected_end_date"))
|
expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
|
||||||
|
|
||||||
if expected_end_date:
|
if expected_end_date:
|
||||||
validate_project_dates(expected_end_date, self, "exp_start_date", "exp_end_date", "Expected")
|
validate_project_dates(getdate(expected_end_date), self, "exp_start_date", "exp_end_date", "Expected")
|
||||||
validate_project_dates(expected_end_date, self, "act_start_date", "act_end_date", "Actual")
|
validate_project_dates(getdate(expected_end_date), self, "act_start_date", "act_end_date", "Actual")
|
||||||
|
|
||||||
def validate_status(self):
|
def validate_status(self):
|
||||||
if self.status!=self.get_db_value("status") and self.status == "Completed":
|
if self.status!=self.get_db_value("status") and self.status == "Completed":
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 62 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
@ -500,6 +500,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
() => {
|
() => {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
me.add_taxes_from_item_tax_template(d.item_tax_rate);
|
||||||
|
if (d.free_item_data) {
|
||||||
|
me.apply_product_discount(d.free_item_data);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn),
|
() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn),
|
||||||
() => me.toggle_conversion_factor(item),
|
() => me.toggle_conversion_factor(item),
|
||||||
@ -1305,6 +1308,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
me.remove_pricing_rule(frappe.get_doc(d.doctype, d.name));
|
me.remove_pricing_rule(frappe.get_doc(d.doctype, d.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (d.free_item_data) {
|
||||||
|
me.apply_product_discount(d.free_item_data);
|
||||||
|
}
|
||||||
|
|
||||||
if (d.apply_rule_on_other_items) {
|
if (d.apply_rule_on_other_items) {
|
||||||
items_rule_dict[d.name] = d;
|
items_rule_dict[d.name] = d;
|
||||||
}
|
}
|
||||||
@ -1334,6 +1341,20 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
apply_product_discount: function(free_item_data) {
|
||||||
|
const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code
|
||||||
|
&& d.is_free_item)) || [];
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
let row_to_modify = frappe.model.add_child(this.frm.doc,
|
||||||
|
this.frm.doc.doctype + ' Item', 'items');
|
||||||
|
|
||||||
|
for (let key in free_item_data) {
|
||||||
|
row_to_modify[key] = free_item_data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
apply_price_list: function(item, reset_plc_conversion) {
|
apply_price_list: function(item, reset_plc_conversion) {
|
||||||
// We need to reset plc_conversion_rate sometimes because the call to
|
// We need to reset plc_conversion_rate sometimes because the call to
|
||||||
// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
|
// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
|
||||||
|
@ -44,12 +44,16 @@ class Gstr2Report(Gstr1Report):
|
|||||||
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
|
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
|
||||||
invoice_details = self.invoices.get(inv)
|
invoice_details = self.invoices.get(inv)
|
||||||
for rate, items in items_based_on_rate.items():
|
for rate, items in items_based_on_rate.items():
|
||||||
|
if inv not in self.igst_invoices:
|
||||||
|
rate = rate / 2
|
||||||
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
||||||
tax_amount = taxable_value * rate / 100
|
tax_amount = taxable_value * rate / 100
|
||||||
if inv in self.igst_invoices:
|
row += [0, tax_amount, tax_amount]
|
||||||
row += [tax_amount, 0, 0]
|
|
||||||
else:
|
else:
|
||||||
row += [0, tax_amount / 2, tax_amount / 2]
|
row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
|
||||||
|
tax_amount = taxable_value * rate / 100
|
||||||
|
row += [tax_amount, 0, 0]
|
||||||
|
|
||||||
|
|
||||||
row += [
|
row += [
|
||||||
self.invoice_cess.get(inv),
|
self.invoice_cess.get(inv),
|
||||||
|
@ -5,13 +5,13 @@ frappe.ui.form.on("Customer", {
|
|||||||
setup: function(frm) {
|
setup: function(frm) {
|
||||||
|
|
||||||
frm.make_methods = {
|
frm.make_methods = {
|
||||||
'Quotation': () => erpnext.utils.create_new_doc('Quotation', {
|
'Quotation': () => frappe.model.open_mapped_doc({
|
||||||
'quotation_to': frm.doc.doctype,
|
method: "erpnext.selling.doctype.customer.customer.make_quotation",
|
||||||
'party_name': frm.doc.name
|
frm: cur_frm
|
||||||
}),
|
}),
|
||||||
'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', {
|
'Opportunity': () => frappe.model.open_mapped_doc({
|
||||||
'opportunity_from': frm.doc.doctype,
|
method: "erpnext.selling.doctype.customer.customer.make_opportunity",
|
||||||
'party_name': frm.doc.name
|
frm: cur_frm
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from erpnext.utilities.transaction_base import TransactionBase
|
|||||||
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
|
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
|
||||||
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
|
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
|
||||||
from frappe.model.rename_doc import update_linked_doctypes
|
from frappe.model.rename_doc import update_linked_doctypes
|
||||||
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
|
||||||
class Customer(TransactionBase):
|
class Customer(TransactionBase):
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
@ -238,6 +239,66 @@ def create_contact(contact, party_type, party, email):
|
|||||||
contact.append('links', dict(link_doctype=party_type, link_name=party))
|
contact.append('links', dict(link_doctype=party_type, link_name=party))
|
||||||
contact.insert()
|
contact.insert()
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_quotation(source_name, target_doc=None):
|
||||||
|
|
||||||
|
def set_missing_values(source, target):
|
||||||
|
_set_missing_values(source, target)
|
||||||
|
|
||||||
|
target_doc = get_mapped_doc("Customer", source_name,
|
||||||
|
{"Customer": {
|
||||||
|
"doctype": "Quotation",
|
||||||
|
"field_map": {
|
||||||
|
"name":"party_name"
|
||||||
|
}
|
||||||
|
}}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
target_doc.quotation_to = "Customer"
|
||||||
|
target_doc.run_method("set_missing_values")
|
||||||
|
target_doc.run_method("set_other_charges")
|
||||||
|
target_doc.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
|
price_list = frappe.get_value("Customer", source_name, 'default_price_list')
|
||||||
|
if price_list:
|
||||||
|
target_doc.selling_price_list = price_list
|
||||||
|
|
||||||
|
return target_doc
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def make_opportunity(source_name, target_doc=None):
|
||||||
|
def set_missing_values(source, target):
|
||||||
|
_set_missing_values(source, target)
|
||||||
|
|
||||||
|
target_doc = get_mapped_doc("Customer", source_name,
|
||||||
|
{"Customer": {
|
||||||
|
"doctype": "Opportunity",
|
||||||
|
"field_map": {
|
||||||
|
"name": "party_name",
|
||||||
|
"doctype": "opportunity_from",
|
||||||
|
}
|
||||||
|
}}, target_doc, set_missing_values)
|
||||||
|
|
||||||
|
return target_doc
|
||||||
|
|
||||||
|
def _set_missing_values(source, target):
|
||||||
|
address = frappe.get_all('Dynamic Link', {
|
||||||
|
'link_doctype': source.doctype,
|
||||||
|
'link_name': source.name,
|
||||||
|
'parenttype': 'Address',
|
||||||
|
}, ['parent'], limit=1)
|
||||||
|
|
||||||
|
contact = frappe.get_all('Dynamic Link', {
|
||||||
|
'link_doctype': source.doctype,
|
||||||
|
'link_name': source.name,
|
||||||
|
'parenttype': 'Contact',
|
||||||
|
}, ['parent'], limit=1)
|
||||||
|
|
||||||
|
if address:
|
||||||
|
target.customer_address = address[0].parent
|
||||||
|
|
||||||
|
if contact:
|
||||||
|
target.contact_person = contact[0].parent
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_loyalty_programs(doc):
|
def get_loyalty_programs(doc):
|
||||||
''' returns applicable loyalty programs for a customer '''
|
''' returns applicable loyalty programs for a customer '''
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_src": "/assets/erpnext/images/illustrations/customers-onboard.png",
|
"image_src": "",
|
||||||
|
"is_completed": 0,
|
||||||
"max_count": 3,
|
"max_count": 3,
|
||||||
"modified": "2019-12-03 22:54:28.959549",
|
"modified": "2019-12-09 17:54:01.686006",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Add A Few Customers",
|
"name": "Add A Few Customers",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
@ -293,7 +293,7 @@ erpnext.pos.PointOfSale = class PointOfSale {
|
|||||||
|
|
||||||
frappe.run_serially([
|
frappe.run_serially([
|
||||||
() => {
|
() => {
|
||||||
this.frm.script_manager.trigger('item_code', item.doctype, item.name)
|
return this.frm.script_manager.trigger('item_code', item.doctype, item.name)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.frm.script_manager.trigger('qty', item.doctype, item.name)
|
this.frm.script_manager.trigger('qty', item.doctype, item.name)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -14,6 +14,7 @@ from frappe.model.document import Document
|
|||||||
from frappe.contacts.address_and_contact import load_address_and_contact
|
from frappe.contacts.address_and_contact import load_address_and_contact
|
||||||
from frappe.utils.nestedset import NestedSet
|
from frappe.utils.nestedset import NestedSet
|
||||||
|
|
||||||
|
from past.builtins import cmp
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
class Company(NestedSet):
|
class Company(NestedSet):
|
||||||
|
@ -106,7 +106,10 @@ def delete_lead_addresses(company_name):
|
|||||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||||
|
|
||||||
def delete_communications(doctype, company_name, company_fieldname):
|
def delete_communications(doctype, company_name, company_fieldname):
|
||||||
frappe.db.sql("""
|
reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
|
||||||
DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND
|
reference_doc_names = [r.name for r in reference_docs]
|
||||||
EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name)
|
|
||||||
""".format(doctype, company_fieldname), (doctype, company_name))
|
communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
|
||||||
|
communication_names = [c.name for c in communications]
|
||||||
|
|
||||||
|
frappe.delete_doc("Communication", communication_names)
|
||||||
|
@ -88,6 +88,57 @@ class TestCompany(unittest.TestCase):
|
|||||||
self.delete_mode_of_payment(template)
|
self.delete_mode_of_payment(template)
|
||||||
frappe.delete_doc("Company", template)
|
frappe.delete_doc("Company", template)
|
||||||
|
|
||||||
|
def test_delete_communication(self):
|
||||||
|
from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
|
||||||
|
company = create_child_company()
|
||||||
|
lead = create_test_lead_in_company(company)
|
||||||
|
communication = create_company_communication("Lead", lead)
|
||||||
|
delete_communications("Lead", "Test Company", "company")
|
||||||
|
self.assertFalse(frappe.db.exists("Communcation", communication))
|
||||||
|
self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
|
||||||
|
|
||||||
def delete_mode_of_payment(self, company):
|
def delete_mode_of_payment(self, company):
|
||||||
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
||||||
where company =%s """, (company))
|
where company =%s """, (company))
|
||||||
|
|
||||||
|
def create_company_communication(doctype, docname):
|
||||||
|
comm = frappe.get_doc({
|
||||||
|
"doctype": "Communication",
|
||||||
|
"communication_type": "Communication",
|
||||||
|
"content": "Deduplication of Links",
|
||||||
|
"communication_medium": "Email",
|
||||||
|
"reference_doctype":doctype,
|
||||||
|
"reference_name":docname
|
||||||
|
})
|
||||||
|
comm.insert()
|
||||||
|
|
||||||
|
def create_child_company():
|
||||||
|
child_company = frappe.db.exists("Company", "Test Company")
|
||||||
|
if not child_company:
|
||||||
|
child_company = frappe.get_doc({
|
||||||
|
"doctype":"Company",
|
||||||
|
"company_name":"Test Company",
|
||||||
|
"abbr":"test_company",
|
||||||
|
"default_currency":"INR"
|
||||||
|
})
|
||||||
|
child_company.insert()
|
||||||
|
else:
|
||||||
|
child_company = frappe.get_doc("Company", child_company)
|
||||||
|
|
||||||
|
return child_company.name
|
||||||
|
|
||||||
|
def create_test_lead_in_company(company):
|
||||||
|
lead = frappe.db.exists("Lead", "Test Lead in new company")
|
||||||
|
if not lead:
|
||||||
|
lead = frappe.get_doc({
|
||||||
|
"doctype": "Lead",
|
||||||
|
"lead_name": "Test Lead in new company",
|
||||||
|
"scompany": company
|
||||||
|
})
|
||||||
|
lead.insert()
|
||||||
|
else:
|
||||||
|
lead = frappe.get_doc("Lead", lead)
|
||||||
|
lead.company = company
|
||||||
|
lead.save()
|
||||||
|
return lead.name
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
"domains": [],
|
"domains": [],
|
||||||
"help_links": [],
|
"help_links": [],
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_src": "/assets/erpnext/images/illustrations/desk-onboard.png",
|
"image_src": "",
|
||||||
"is_completed": 0,
|
"is_completed": 0,
|
||||||
"max_count": 3,
|
"max_count": 3,
|
||||||
"modified": "2019-12-04 19:21:39.995776",
|
"modified": "2019-12-09 17:53:53.849953",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Welcome back to ERPNext!",
|
"name": "Welcome back to ERPNext!",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
@ -7,13 +7,14 @@
|
|||||||
"domains": [],
|
"domains": [],
|
||||||
"help_links": [],
|
"help_links": [],
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_src": "/assets/erpnext/images/illustrations/desk-onboard.png",
|
"image_src": "",
|
||||||
|
"is_completed": 0,
|
||||||
"max_count": 0,
|
"max_count": 0,
|
||||||
"modified": "2019-12-03 22:49:12.871260",
|
"modified": "2019-12-22 21:26:28.414597",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Welcome to ERPNext!",
|
"name": "Welcome to ERPNext!",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!",
|
"slide_desc": "<div class=\"text center\">Setting up an ERP can be overwhelming. But don't worry, we have got your back! This wizard will help you onboard to ERPNext in a short time!</div>",
|
||||||
"slide_fields": [],
|
"slide_fields": [],
|
||||||
"slide_module": "Setup",
|
"slide_module": "Setup",
|
||||||
"slide_order": 1,
|
"slide_order": 1,
|
||||||
|
@ -135,8 +135,7 @@
|
|||||||
"publish_in_hub",
|
"publish_in_hub",
|
||||||
"hub_category_to_publish",
|
"hub_category_to_publish",
|
||||||
"hub_warehouse",
|
"hub_warehouse",
|
||||||
"synced_with_hub",
|
"synced_with_hub"
|
||||||
"manufacturers"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -1016,12 +1015,6 @@
|
|||||||
"label": "Synced With Hub",
|
"label": "Synced With Hub",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "manufacturers",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"label": "Manufacturers",
|
|
||||||
"options": "Item Manufacturer"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.__islocal",
|
"depends_on": "eval:!doc.__islocal",
|
||||||
"fieldname": "over_delivery_receipt_allowance",
|
"fieldname": "over_delivery_receipt_allowance",
|
||||||
@ -1049,7 +1042,7 @@
|
|||||||
"idx": 2,
|
"idx": 2,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"max_attachments": 1,
|
"max_attachments": 1,
|
||||||
"modified": "2019-10-09 17:05:59.576119",
|
"modified": "2019-12-13 12:15:56.197246",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
@ -125,7 +125,6 @@ class Item(WebsiteGenerator):
|
|||||||
self.validate_auto_reorder_enabled_in_stock_settings()
|
self.validate_auto_reorder_enabled_in_stock_settings()
|
||||||
self.cant_change()
|
self.cant_change()
|
||||||
self.update_show_in_website()
|
self.update_show_in_website()
|
||||||
self.validate_manufacturer()
|
|
||||||
|
|
||||||
if not self.get("__islocal"):
|
if not self.get("__islocal"):
|
||||||
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
|
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
|
||||||
@ -145,13 +144,6 @@ class Item(WebsiteGenerator):
|
|||||||
if cint(frappe.db.get_single_value('Stock Settings', 'clean_description_html')):
|
if cint(frappe.db.get_single_value('Stock Settings', 'clean_description_html')):
|
||||||
self.description = clean_html(self.description)
|
self.description = clean_html(self.description)
|
||||||
|
|
||||||
def validate_manufacturer(self):
|
|
||||||
list_man = [(x.manufacturer, x.manufacturer_part_no) for x in self.get('manufacturers')]
|
|
||||||
set_man = set(list_man)
|
|
||||||
|
|
||||||
if len(list_man) != len(set_man):
|
|
||||||
frappe.throw(_("Duplicate entry in Manufacturers table"))
|
|
||||||
|
|
||||||
def validate_customer_provided_part(self):
|
def validate_customer_provided_part(self):
|
||||||
if self.is_customer_provided_item:
|
if self.is_customer_provided_item:
|
||||||
if self.is_purchase_item:
|
if self.is_purchase_item:
|
||||||
|
@ -622,7 +622,7 @@ frappe.ui.form.on('Stock Entry Detail', {
|
|||||||
if(r.message) {
|
if(r.message) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
$.each(r.message, function(k, v) {
|
$.each(r.message, function(k, v) {
|
||||||
d[k] = v;
|
frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered
|
||||||
});
|
});
|
||||||
refresh_field("items");
|
refresh_field("items");
|
||||||
erpnext.stock.select_batch_and_serial_no(frm, d);
|
erpnext.stock.select_batch_and_serial_no(frm, d);
|
||||||
|
@ -372,7 +372,7 @@ class StockEntry(StockController):
|
|||||||
elif d.t_warehouse and not d.basic_rate:
|
elif d.t_warehouse and not d.basic_rate:
|
||||||
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
||||||
self.doctype, self.name, d.allow_zero_valuation_rate,
|
self.doctype, self.name, d.allow_zero_valuation_rate,
|
||||||
currency=erpnext.get_company_currency(self.company))
|
currency=erpnext.get_company_currency(self.company), company=self.company)
|
||||||
|
|
||||||
def set_actual_qty(self):
|
def set_actual_qty(self):
|
||||||
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
|
||||||
@ -649,6 +649,12 @@ class StockEntry(StockController):
|
|||||||
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
|
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
|
||||||
|
|
||||||
total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
|
total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
|
||||||
|
divide_based_on = total_basic_amount
|
||||||
|
|
||||||
|
if self.get("additional_costs") and not total_basic_amount:
|
||||||
|
# if total_basic_amount is 0, distribute additional charges based on qty
|
||||||
|
divide_based_on = sum(item.qty for item in list(self.get("items")))
|
||||||
|
|
||||||
item_account_wise_additional_cost = {}
|
item_account_wise_additional_cost = {}
|
||||||
|
|
||||||
for t in self.get("additional_costs"):
|
for t in self.get("additional_costs"):
|
||||||
@ -656,8 +662,11 @@ class StockEntry(StockController):
|
|||||||
if d.t_warehouse:
|
if d.t_warehouse:
|
||||||
item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
|
item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
|
||||||
item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
|
item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
|
||||||
|
|
||||||
|
multiply_based_on = d.basic_amount if total_basic_amount else d.qty
|
||||||
|
|
||||||
item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
|
item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
|
||||||
(t.amount * d.basic_amount) / total_basic_amount
|
(t.amount * multiply_based_on) / divide_based_on
|
||||||
|
|
||||||
if item_account_wise_additional_cost:
|
if item_account_wise_additional_cost:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
|
@ -790,6 +790,50 @@ class TestStockEntry(unittest.TestCase):
|
|||||||
filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening")
|
filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening")
|
||||||
self.assertEqual(is_opening, "Yes")
|
self.assertEqual(is_opening, "Yes")
|
||||||
|
|
||||||
|
def test_total_basic_amount_zero(self):
|
||||||
|
se = frappe.get_doc({"doctype":"Stock Entry",
|
||||||
|
"purpose":"Material Receipt",
|
||||||
|
"stock_entry_type":"Material Receipt",
|
||||||
|
"posting_date": nowdate(),
|
||||||
|
"company":"_Test Company with perpetual inventory",
|
||||||
|
"items":[
|
||||||
|
{
|
||||||
|
"item_code":"Basil Leaves",
|
||||||
|
"description":"Basil Leaves",
|
||||||
|
"qty": 1,
|
||||||
|
"basic_rate": 0,
|
||||||
|
"uom":"Nos",
|
||||||
|
"t_warehouse": "Stores - TCP1",
|
||||||
|
"allow_zero_valuation_rate": 1,
|
||||||
|
"cost_center": "Main - TCP1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_code":"Basil Leaves",
|
||||||
|
"description":"Basil Leaves",
|
||||||
|
"qty": 2,
|
||||||
|
"basic_rate": 0,
|
||||||
|
"uom":"Nos",
|
||||||
|
"t_warehouse": "Stores - TCP1",
|
||||||
|
"allow_zero_valuation_rate": 1,
|
||||||
|
"cost_center": "Main - TCP1"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"additional_costs":[
|
||||||
|
{"expense_account":"Miscellaneous Expenses - TCP1",
|
||||||
|
"amount":100,
|
||||||
|
"description": "miscellanous"}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
se.insert()
|
||||||
|
se.submit()
|
||||||
|
|
||||||
|
self.check_gl_entries("Stock Entry", se.name,
|
||||||
|
sorted([
|
||||||
|
["Stock Adjustment - TCP1", 100.0, 0.0],
|
||||||
|
["Miscellaneous Expenses - TCP1", 0.0, 100.0]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
||||||
se = frappe.copy_doc(test_records[0])
|
se = frappe.copy_doc(test_records[0])
|
||||||
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
||||||
|
@ -7,9 +7,10 @@
|
|||||||
"domains": [],
|
"domains": [],
|
||||||
"help_links": [],
|
"help_links": [],
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"image_src": "/assets/erpnext/images/illustrations/products-onboard.png",
|
"image_src": "",
|
||||||
|
"is_completed": 0,
|
||||||
"max_count": 3,
|
"max_count": 3,
|
||||||
"modified": "2019-12-03 22:54:07.558632",
|
"modified": "2019-12-09 17:54:09.602885",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"name": "Add A Few Products You Buy Or Sell",
|
"name": "Add A Few Products You Buy Or Sell",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
@ -24,20 +24,15 @@ async function get_global_variables() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setup_timezone_selector() {
|
function setup_timezone_selector() {
|
||||||
/**
|
|
||||||
* window.timezones is a dictionary with the following structure
|
|
||||||
* { IANA name: Pretty name}
|
|
||||||
* For example : { Asia/Kolkata : "India Time - Asia/Kolkata"}
|
|
||||||
*/
|
|
||||||
let timezones_element = document.getElementById('appointment-timezone');
|
let timezones_element = document.getElementById('appointment-timezone');
|
||||||
let offset = new Date().getTimezoneOffset();
|
let local_timezone = moment.tz.guess()
|
||||||
Object.keys(window.timezones).forEach((timezone) => {
|
window.timezones.forEach(timezone => {
|
||||||
let opt = document.createElement('option');
|
let opt = document.createElement('option');
|
||||||
opt.value = timezone;
|
opt.value = timezone;
|
||||||
if (timezone == moment.tz.guess()) {
|
if (timezone == local_timezone) {
|
||||||
opt.selected = true;
|
opt.selected = true;
|
||||||
}
|
}
|
||||||
opt.innerHTML = window.timezones[timezone]
|
opt.innerHTML = timezone;
|
||||||
timezones_element.appendChild(opt)
|
timezones_element.appendChild(opt)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -114,7 +109,7 @@ function get_timeslot_div_layout(timeslot) {
|
|||||||
timeslot_div.classList.add('unavailable')
|
timeslot_div.classList.add('unavailable')
|
||||||
}
|
}
|
||||||
timeslot_div.innerHTML = get_slot_layout(start_time);
|
timeslot_div.innerHTML = get_slot_layout(start_time);
|
||||||
timeslot_div.id = timeslot.time.substr(11, 20);
|
timeslot_div.id = timeslot.time.substring(11, 19);
|
||||||
timeslot_div.addEventListener('click', select_time);
|
timeslot_div.addEventListener('click', select_time);
|
||||||
return timeslot_div
|
return timeslot_div
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,8 @@ def get_appointment_settings():
|
|||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def get_timezones():
|
def get_timezones():
|
||||||
from babel.dates import get_timezone, get_timezone_name, Locale
|
import pytz
|
||||||
from frappe.utils.momentjs import get_all_timezones
|
return pytz.all_timezones
|
||||||
|
|
||||||
translated_dict = {}
|
|
||||||
locale = Locale.parse(frappe.local.lang, sep="-")
|
|
||||||
|
|
||||||
for tz in get_all_timezones():
|
|
||||||
timezone_name = get_timezone_name(get_timezone(tz), locale=locale, width='short')
|
|
||||||
if timezone_name:
|
|
||||||
translated_dict[tz] = timezone_name + ' - ' + tz
|
|
||||||
|
|
||||||
return translated_dict
|
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def get_appointment_slots(date, timezone):
|
def get_appointment_slots(date, timezone):
|
||||||
@ -90,7 +80,7 @@ def get_available_slots_between(query_start_time, query_end_time, settings):
|
|||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def create_appointment(date, time, tz, contact):
|
def create_appointment(date, time, tz, contact):
|
||||||
format_string = '%Y-%m-%d %H:%M:%S%z'
|
format_string = '%Y-%m-%d %H:%M:%S'
|
||||||
scheduled_time = datetime.datetime.strptime(date + " " + time, format_string)
|
scheduled_time = datetime.datetime.strptime(date + " " + time, format_string)
|
||||||
# Strip tzinfo from datetime objects since it's handled by the doctype
|
# Strip tzinfo from datetime objects since it's handled by the doctype
|
||||||
scheduled_time = scheduled_time.replace(tzinfo = None)
|
scheduled_time = scheduled_time.replace(tzinfo = None)
|
||||||
|
Loading…
Reference in New Issue
Block a user