Merge branch 'staging-fixes' into company_address
This commit is contained in:
commit
7bb7f95aa8
@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '10.1.76'
|
__version__ = '10.1.77'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
@ -39,6 +39,8 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
|
|||||||
});
|
});
|
||||||
frm.events.get_total_gain_loss(frm);
|
frm.events.get_total_gain_loss(frm);
|
||||||
refresh_field("accounts");
|
refresh_field("accounts");
|
||||||
|
} else {
|
||||||
|
frappe.msgprint(__("No records found"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -67,17 +67,19 @@ class ExchangeRateRevaluation(Document):
|
|||||||
and account_currency != %s
|
and account_currency != %s
|
||||||
order by name""",(self.company, company_currency))
|
order by name""",(self.company, company_currency))
|
||||||
|
|
||||||
account_details = frappe.db.sql("""
|
account_details = []
|
||||||
select
|
if accounts:
|
||||||
account, party_type, party, account_currency,
|
account_details = frappe.db.sql("""
|
||||||
sum(debit_in_account_currency) - sum(credit_in_account_currency) as balance_in_account_currency,
|
select
|
||||||
sum(debit) - sum(credit) as balance
|
account, party_type, party, account_currency,
|
||||||
from `tabGL Entry`
|
sum(debit_in_account_currency) - sum(credit_in_account_currency) as balance_in_account_currency,
|
||||||
where account in (%s)
|
sum(debit) - sum(credit) as balance
|
||||||
group by account, party_type, party
|
from `tabGL Entry`
|
||||||
having sum(debit) != sum(credit)
|
where account in (%s)
|
||||||
order by account
|
group by account, party_type, party
|
||||||
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
|
having sum(debit) != sum(credit)
|
||||||
|
order by account
|
||||||
|
""" % ', '.join(['%s']*len(accounts)), tuple(accounts), as_dict=1)
|
||||||
|
|
||||||
return account_details
|
return account_details
|
||||||
|
|
||||||
|
@ -18,15 +18,14 @@ class GLEntry(Document):
|
|||||||
self.flags.ignore_submit_comment = True
|
self.flags.ignore_submit_comment = True
|
||||||
self.check_mandatory()
|
self.check_mandatory()
|
||||||
self.validate_and_set_fiscal_year()
|
self.validate_and_set_fiscal_year()
|
||||||
|
self.pl_must_have_cost_center()
|
||||||
|
self.validate_cost_center()
|
||||||
|
|
||||||
if not self.flags.from_repost:
|
if not self.flags.from_repost:
|
||||||
self.pl_must_have_cost_center()
|
|
||||||
self.check_pl_account()
|
self.check_pl_account()
|
||||||
self.validate_cost_center()
|
|
||||||
self.validate_party()
|
self.validate_party()
|
||||||
self.validate_currency()
|
self.validate_currency()
|
||||||
|
|
||||||
|
|
||||||
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
|
||||||
if not from_repost:
|
if not from_repost:
|
||||||
self.validate_account_details(adv_adj)
|
self.validate_account_details(adv_adj)
|
||||||
|
@ -200,7 +200,7 @@ class GrossProfitGenerator(object):
|
|||||||
|
|
||||||
def skip_row(self, row, product_bundles):
|
def skip_row(self, row, product_bundles):
|
||||||
if self.filters.get("group_by") != "Invoice":
|
if self.filters.get("group_by") != "Invoice":
|
||||||
if not row.get(scrub(self.filters.get("group_by"))):
|
if not row.get(scrub(self.filters.get("group_by", ""))):
|
||||||
return True
|
return True
|
||||||
elif row.get("is_return") == 1:
|
elif row.get("is_return") == 1:
|
||||||
return True
|
return True
|
||||||
@ -316,7 +316,7 @@ class GrossProfitGenerator(object):
|
|||||||
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
||||||
{sales_team_table}
|
{sales_team_table}
|
||||||
where
|
where
|
||||||
`tabSales Invoice`.docstatus=1 {conditions} {match_cond}
|
`tabSales Invoice`.docstatus=1 and `tabSales Invoice`.is_opening!='Yes' {conditions} {match_cond}
|
||||||
order by
|
order by
|
||||||
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
|
||||||
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
.format(conditions=conditions, sales_person_cols=sales_person_cols,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
|
"allow_events_in_timeline": 0,
|
||||||
"allow_guest_to_view": 0,
|
"allow_guest_to_view": 0,
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
@ -154,7 +155,7 @@
|
|||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fetch_from": "item_code.asset_category",
|
"fetch_from": "item_code.asset_category",
|
||||||
"fieldname": "asset_category",
|
"fieldname": "asset_category",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
@ -165,12 +166,12 @@
|
|||||||
"label": "Asset Category",
|
"label": "Asset Category",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"options": "",
|
"options": "Asset Category",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"read_only": 0,
|
"read_only": 1,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 0,
|
"reqd": 0,
|
||||||
@ -1881,7 +1882,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-08-21 14:44:24.507215",
|
"modified": "2019-01-15 16:12:48.314196",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset",
|
"name": "Asset",
|
||||||
|
@ -499,7 +499,8 @@ def get_bin_details(row):
|
|||||||
conditions = ""
|
conditions = ""
|
||||||
warehouse = row.source_warehouse or row.default_warehouse or row.warehouse
|
warehouse = row.source_warehouse or row.default_warehouse or row.warehouse
|
||||||
if warehouse:
|
if warehouse:
|
||||||
conditions = " and warehouse='{0}'".format(frappe.db.escape(warehouse))
|
lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||||
|
conditions = " and exists(select name from `tabWarehouse` where lft >= {0} and rgt <= {1} and name=`tabBin`.warehouse)".format(lft, rgt)
|
||||||
|
|
||||||
item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
|
item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
|
||||||
ifnull(sum(actual_qty),0) as actual_qty from `tabBin`
|
ifnull(sum(actual_qty),0) as actual_qty from `tabBin`
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
execute:import unidecode # new requirement
|
execute:import unidecode # new requirement
|
||||||
erpnext.patches.v8_0.move_perpetual_inventory_setting
|
erpnext.patches.v8_0.move_perpetual_inventory_setting
|
||||||
|
erpnext.patches.v11_0.rename_production_order_to_work_order
|
||||||
erpnext.patches.v11_0.refactor_naming_series
|
erpnext.patches.v11_0.refactor_naming_series
|
||||||
erpnext.patches.v11_0.refactor_autoname_naming
|
erpnext.patches.v11_0.refactor_autoname_naming
|
||||||
erpnext.patches.v10_0.rename_schools_to_education
|
erpnext.patches.v10_0.rename_schools_to_education
|
||||||
erpnext.patches.v11_0.rename_production_order_to_work_order
|
|
||||||
erpnext.patches.v4_0.validate_v3_patch
|
erpnext.patches.v4_0.validate_v3_patch
|
||||||
erpnext.patches.v4_0.fix_employee_user_id
|
erpnext.patches.v4_0.fix_employee_user_id
|
||||||
erpnext.patches.v4_0.remove_employee_role_if_no_employee
|
erpnext.patches.v4_0.remove_employee_role_if_no_employee
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.rename_doc import rename_doc
|
from frappe.model.rename_doc import rename_doc
|
||||||
from frappe.model.utils.rename_field import rename_field
|
from frappe.model.utils.rename_field import rename_field
|
||||||
|
@ -12,6 +12,7 @@ from frappe.utils.nestedset import NestedSet
|
|||||||
|
|
||||||
|
|
||||||
class CircularReferenceError(frappe.ValidationError): pass
|
class CircularReferenceError(frappe.ValidationError): pass
|
||||||
|
class EndDateCannotBeGreaterThanProjectEndDateError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class Task(NestedSet):
|
class Task(NestedSet):
|
||||||
nsm_parent_field = 'parent_task'
|
nsm_parent_field = 'parent_task'
|
||||||
@ -43,6 +44,12 @@ class Task(NestedSet):
|
|||||||
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
|
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
|
||||||
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
|
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
|
||||||
|
|
||||||
|
if(self.project):
|
||||||
|
if frappe.db.exists("Project", self.project):
|
||||||
|
expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
|
||||||
|
if self.exp_end_date and expected_end_date and getdate(self.exp_end_date) > getdate(expected_end_date) :
|
||||||
|
frappe.throw(_("Expected end date cannot be after Project: <b>'{0}'</b> Expected end date").format(self.project), EndDateCannotBeGreaterThanProjectEndDateError)
|
||||||
|
|
||||||
def validate_status(self):
|
def validate_status(self):
|
||||||
if self.status!=self.get_db_value("status") and self.status == "Closed":
|
if self.status!=self.get_db_value("status") and self.status == "Closed":
|
||||||
for d in self.depends_on:
|
for d in self.depends_on:
|
||||||
|
@ -5,11 +5,11 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import getdate, nowdate, add_days
|
from frappe.utils import getdate, nowdate, add_days
|
||||||
|
|
||||||
from erpnext.projects.doctype.task.task import CircularReferenceError
|
from erpnext.projects.doctype.task.task import CircularReferenceError, EndDateCannotBeGreaterThanProjectEndDateError
|
||||||
|
|
||||||
class TestTask(unittest.TestCase):
|
class TestTask(unittest.TestCase):
|
||||||
def test_circular_reference(self):
|
def test_circular_reference(self):
|
||||||
task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10))
|
task1 = create_task("_Test Task 1", add_days(nowdate(), -15), add_days(nowdate(), -10))
|
||||||
task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name)
|
task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name)
|
||||||
task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name)
|
task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name)
|
||||||
|
|
||||||
@ -97,7 +97,16 @@ class TestTask(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
|
self.assertEqual(frappe.db.get_value("Task", task.name, "status"), "Overdue")
|
||||||
|
|
||||||
def create_task(subject, start=None, end=None, depends_on=None, project=None):
|
def test_end_date_validation(self):
|
||||||
|
task_end = create_task("Testing_Enddate_validation", add_days(nowdate(), 35), add_days(nowdate(), 45), save=False)
|
||||||
|
pro = frappe.get_doc("Project", task_end.project)
|
||||||
|
pro.expected_end_date = add_days(nowdate(), 40)
|
||||||
|
pro.save()
|
||||||
|
self.assertRaises(EndDateCannotBeGreaterThanProjectEndDateError, task_end.save)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_task(subject, start=None, end=None, depends_on=None, project=None, save=True):
|
||||||
if not frappe.db.exists("Task", subject):
|
if not frappe.db.exists("Task", subject):
|
||||||
task = frappe.new_doc('Task')
|
task = frappe.new_doc('Task')
|
||||||
task.status = "Open"
|
task.status = "Open"
|
||||||
@ -105,7 +114,8 @@ def create_task(subject, start=None, end=None, depends_on=None, project=None):
|
|||||||
task.exp_start_date = start or nowdate()
|
task.exp_start_date = start or nowdate()
|
||||||
task.exp_end_date = end or nowdate()
|
task.exp_end_date = end or nowdate()
|
||||||
task.project = project or "_Test Project"
|
task.project = project or "_Test Project"
|
||||||
task.save()
|
if save:
|
||||||
|
task.save()
|
||||||
else:
|
else:
|
||||||
task = frappe.get_doc("Task", subject)
|
task = frappe.get_doc("Task", subject)
|
||||||
|
|
||||||
@ -113,6 +123,7 @@ def create_task(subject, start=None, end=None, depends_on=None, project=None):
|
|||||||
task.append("depends_on", {
|
task.append("depends_on", {
|
||||||
"task": depends_on
|
"task": depends_on
|
||||||
})
|
})
|
||||||
task.save()
|
if save:
|
||||||
|
task.save()
|
||||||
|
|
||||||
return task
|
return task
|
@ -416,6 +416,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
item_code: item.item_code,
|
item_code: item.item_code,
|
||||||
barcode: item.barcode,
|
barcode: item.barcode,
|
||||||
serial_no: item.serial_no,
|
serial_no: item.serial_no,
|
||||||
|
set_warehouse: me.frm.doc.set_warehouse,
|
||||||
warehouse: item.warehouse,
|
warehouse: item.warehouse,
|
||||||
customer: me.frm.doc.customer,
|
customer: me.frm.doc.customer,
|
||||||
supplier: me.frm.doc.supplier,
|
supplier: me.frm.doc.supplier,
|
||||||
|
@ -11,22 +11,49 @@ def validate_gstin_for_india(doc, method):
|
|||||||
if not hasattr(doc, 'gstin'):
|
if not hasattr(doc, 'gstin'):
|
||||||
return
|
return
|
||||||
|
|
||||||
if doc.gstin:
|
doc.gstin = doc.gstin.upper().strip()
|
||||||
doc.gstin = doc.gstin.upper()
|
if not doc.gstin or doc.gstin == 'NA':
|
||||||
if doc.gstin not in ["NA", "na"]:
|
return
|
||||||
p = re.compile("[0-9]{2}[a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9a-zA-Z]{1}")
|
|
||||||
if not p.match(doc.gstin):
|
if len(doc.gstin) != 15:
|
||||||
frappe.throw(_("Invalid GSTIN or Enter NA for Unregistered"))
|
frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters."))
|
||||||
|
|
||||||
|
p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
|
||||||
|
if not p.match(doc.gstin):
|
||||||
|
frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
|
||||||
|
|
||||||
|
validate_gstin_check_digit(doc.gstin)
|
||||||
|
|
||||||
if not doc.gst_state:
|
if not doc.gst_state:
|
||||||
if doc.state in states:
|
if not doc.state:
|
||||||
doc.gst_state = doc.state
|
return
|
||||||
|
state = doc.state.lower()
|
||||||
|
states_lowercase = {s.lower():s for s in states}
|
||||||
|
if state in states_lowercase:
|
||||||
|
doc.gst_state = states_lowercase[state]
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
if doc.gst_state:
|
doc.gst_state_number = state_numbers[doc.gst_state]
|
||||||
doc.gst_state_number = state_numbers[doc.gst_state]
|
if doc.gst_state_number != doc.gstin[:2]:
|
||||||
if doc.gstin and doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
|
frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
|
||||||
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
|
.format(doc.gst_state_number))
|
||||||
.format(doc.gst_state_number))
|
|
||||||
|
def validate_gstin_check_digit(gstin):
|
||||||
|
''' Function to validate the check digit of the GSTIN.'''
|
||||||
|
factor = 1
|
||||||
|
total = 0
|
||||||
|
code_point_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
mod = len(code_point_chars)
|
||||||
|
input_chars = gstin[:-1]
|
||||||
|
for char in input_chars:
|
||||||
|
digit = factor * code_point_chars.find(char)
|
||||||
|
digit = (digit // mod) + (digit % mod)
|
||||||
|
total += digit
|
||||||
|
factor = 2 if factor == 1 else 1
|
||||||
|
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
|
||||||
|
frappe.throw(_("Invalid GSTIN! The check digit validation has failed. " +
|
||||||
|
"Please ensure you've typed the GSTIN correctly."))
|
||||||
|
|
||||||
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
|
||||||
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
|
||||||
|
@ -177,6 +177,11 @@ class Customer(TransactionBase):
|
|||||||
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
|
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
|
||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
|
if self.customer_primary_contact:
|
||||||
|
frappe.db.sql("""update `tabCustomer`
|
||||||
|
set customer_primary_contact=null, mobile_no=null, email_id=null
|
||||||
|
where name=%s""", self.name)
|
||||||
|
|
||||||
delete_contact_and_address('Customer', self.name)
|
delete_contact_and_address('Customer', self.name)
|
||||||
if self.lead_name:
|
if self.lead_name:
|
||||||
frappe.db.sql("update `tabLead` set status='Interested' where name=%s", self.lead_name)
|
frappe.db.sql("update `tabLead` set status='Interested' where name=%s", self.lead_name)
|
||||||
|
@ -98,6 +98,15 @@ class TestCustomer(unittest.TestCase):
|
|||||||
|
|
||||||
so.save()
|
so.save()
|
||||||
|
|
||||||
|
def test_delete_customer_contact(self):
|
||||||
|
customer = frappe.get_doc(
|
||||||
|
get_customer_dict('_Test Customer for delete')).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
customer.mobile_no = "8989889890"
|
||||||
|
customer.save()
|
||||||
|
self.assertTrue(customer.customer_primary_contact)
|
||||||
|
frappe.delete_doc('Customer', customer.name)
|
||||||
|
|
||||||
def test_disabled_customer(self):
|
def test_disabled_customer(self):
|
||||||
make_test_records("Item")
|
make_test_records("Item")
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _, scrub
|
from frappe import _, scrub
|
||||||
from frappe.utils import getdate, flt
|
from frappe.utils import getdate, flt, add_to_date, add_days
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class Analytics(object):
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"width": 140
|
"width": 140
|
||||||
})
|
})
|
||||||
for dummy, end_date in self.periodic_daterange:
|
for end_date in self.periodic_daterange:
|
||||||
period = self.get_period(end_date)
|
period = self.get_period(end_date)
|
||||||
self.columns.append({
|
self.columns.append({
|
||||||
"label": _(period),
|
"label": _(period),
|
||||||
@ -169,7 +169,7 @@ class Analytics(object):
|
|||||||
"entity_name": self.entity_names.get(entity)
|
"entity_name": self.entity_names.get(entity)
|
||||||
}
|
}
|
||||||
total = 0
|
total = 0
|
||||||
for dummy, end_date in self.periodic_daterange:
|
for end_date in self.periodic_daterange:
|
||||||
period = self.get_period(end_date)
|
period = self.get_period(end_date)
|
||||||
amount = flt(period_data.get(period, 0.0))
|
amount = flt(period_data.get(period, 0.0))
|
||||||
row[scrub(period)] = amount
|
row[scrub(period)] = amount
|
||||||
@ -188,7 +188,7 @@ class Analytics(object):
|
|||||||
"indent": self.depth_map.get(d.name)
|
"indent": self.depth_map.get(d.name)
|
||||||
}
|
}
|
||||||
total = 0
|
total = 0
|
||||||
for dummy, end_date in self.periodic_daterange:
|
for end_date in self.periodic_daterange:
|
||||||
period = self.get_period(end_date)
|
period = self.get_period(end_date)
|
||||||
amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0))
|
amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0))
|
||||||
row[scrub(period)] = amount
|
row[scrub(period)] = amount
|
||||||
@ -219,12 +219,11 @@ class Analytics(object):
|
|||||||
period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year)
|
period = "Quarter " + str(((posting_date.month-1)//3)+1) +" " + str(posting_date.year)
|
||||||
else:
|
else:
|
||||||
year = get_fiscal_year(posting_date, company=self.filters.company)
|
year = get_fiscal_year(posting_date, company=self.filters.company)
|
||||||
period = str(year[2])
|
period = str(year[0])
|
||||||
|
|
||||||
return period
|
return period
|
||||||
|
|
||||||
def get_period_date_ranges(self):
|
def get_period_date_ranges(self):
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta, MO
|
||||||
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
|
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
|
||||||
|
|
||||||
increment = {
|
increment = {
|
||||||
@ -234,18 +233,26 @@ class Analytics(object):
|
|||||||
"Yearly": 12
|
"Yearly": 12
|
||||||
}.get(self.filters.range, 1)
|
}.get(self.filters.range, 1)
|
||||||
|
|
||||||
|
if self.filters.range in ['Monthly', 'Quarterly']:
|
||||||
|
from_date = from_date.replace(day = 1)
|
||||||
|
elif self.filters.range == "Yearly":
|
||||||
|
from_date = get_fiscal_year(from_date)[1]
|
||||||
|
else:
|
||||||
|
from_date = from_date + relativedelta(from_date, weekday=MO(-1))
|
||||||
|
|
||||||
self.periodic_daterange = []
|
self.periodic_daterange = []
|
||||||
for dummy in range(1, 53, increment):
|
for dummy in range(1, 53):
|
||||||
if self.filters.range == "Weekly":
|
if self.filters.range == "Weekly":
|
||||||
period_end_date = from_date + relativedelta(days=6)
|
period_end_date = add_days(from_date, 6)
|
||||||
else:
|
else:
|
||||||
period_end_date = from_date + relativedelta(months=increment, days=-1)
|
period_end_date = add_to_date(from_date, months=increment, days=-1)
|
||||||
|
|
||||||
if period_end_date > to_date:
|
if period_end_date > to_date:
|
||||||
period_end_date = to_date
|
period_end_date = to_date
|
||||||
self.periodic_daterange.append([from_date, period_end_date])
|
|
||||||
|
|
||||||
from_date = period_end_date + relativedelta(days=1)
|
self.periodic_daterange.append(period_end_date)
|
||||||
|
|
||||||
|
from_date = add_days(period_end_date, 1)
|
||||||
if period_end_date == to_date:
|
if period_end_date == to_date:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
doctype_list = [
|
doctype_list = [
|
||||||
|
@ -13,7 +13,7 @@ def get_data():
|
|||||||
'goal_doctype_link': 'company',
|
'goal_doctype_link': 'company',
|
||||||
'goal_field': 'base_grand_total',
|
'goal_field': 'base_grand_total',
|
||||||
'date_field': 'posting_date',
|
'date_field': 'posting_date',
|
||||||
'filter_str': 'docstatus = 1',
|
'filter_str': "docstatus = 1 and is_opening != 'Yes'",
|
||||||
'aggregation': 'sum'
|
'aggregation': 'sum'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -136,7 +136,10 @@ def get_child_groups_for_list_in_html(item_group, start, limit, search):
|
|||||||
rgt = ('<', item_group.rgt),
|
rgt = ('<', item_group.rgt),
|
||||||
),
|
),
|
||||||
or_filters = search_filters,
|
or_filters = search_filters,
|
||||||
order_by = 'weightage desc, name asc')
|
order_by = 'weightage desc, name asc',
|
||||||
|
start = start,
|
||||||
|
limit = limit
|
||||||
|
)
|
||||||
|
|
||||||
return [get_item_for_list_in_html(r) for r in data]
|
return [get_item_for_list_in_html(r) for r in data]
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@ from frappe.utils import flt, nowdate, nowtime
|
|||||||
from erpnext.accounts.utils import get_stock_and_account_difference
|
from erpnext.accounts.utils import get_stock_and_account_difference
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||||
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
|
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
|
||||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError
|
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
|
||||||
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
|
||||||
class TestStockReconciliation(unittest.TestCase):
|
class TestStockReconciliation(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -79,6 +81,17 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
|
|
||||||
set_perpetual_inventory(0)
|
set_perpetual_inventory(0)
|
||||||
|
|
||||||
|
def test_get_items(self):
|
||||||
|
create_warehouse("_Test Warehouse Group 1", {"is_group": 1})
|
||||||
|
create_warehouse("_Test Warehouse Ledger 1", {"is_group": 0, "parent_warehouse": "_Test Warehouse Group 1 - _TC"})
|
||||||
|
make_item("_Test Stock Reco Item", {"default_warehouse": "_Test Warehouse Ledger 1 - _TC",
|
||||||
|
"is_stock_item": 1, "opening_stock": 100, "valuation_rate": 100})
|
||||||
|
|
||||||
|
items = get_items("_Test Warehouse Group 1 - _TC", nowdate(), nowtime())
|
||||||
|
|
||||||
|
self.assertEqual(["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100],
|
||||||
|
[items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]])
|
||||||
|
|
||||||
def insert_existing_sle(self):
|
def insert_existing_sle(self):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ class TestWarehouse(unittest.TestCase):
|
|||||||
self.assertTrue(frappe.db.get_value("Warehouse",
|
self.assertTrue(frappe.db.get_value("Warehouse",
|
||||||
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
|
filters={"account": "Test Warehouse for Merging 2 - _TC"}))
|
||||||
|
|
||||||
def create_warehouse(warehouse_name):
|
def create_warehouse(warehouse_name, properties=None):
|
||||||
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
|
if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
|
||||||
w = frappe.new_doc("Warehouse")
|
w = frappe.new_doc("Warehouse")
|
||||||
w.warehouse_name = warehouse_name
|
w.warehouse_name = warehouse_name
|
||||||
@ -98,11 +98,13 @@ def create_warehouse(warehouse_name):
|
|||||||
w.company = "_Test Company"
|
w.company = "_Test Company"
|
||||||
make_account_for_warehouse(warehouse_name, w)
|
make_account_for_warehouse(warehouse_name, w)
|
||||||
w.account = warehouse_name + " - _TC"
|
w.account = warehouse_name + " - _TC"
|
||||||
|
if properties:
|
||||||
|
w.update(properties)
|
||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
def make_account_for_warehouse(warehouse_name, warehouse_obj):
|
def make_account_for_warehouse(warehouse_name, warehouse_obj):
|
||||||
if not frappe.db.exists("Account", warehouse_name + " - _TC"):
|
if not frappe.db.exists("Account", warehouse_name + " - _TC"):
|
||||||
parent_account = frappe.db.get_value('Account',
|
parent_account = frappe.db.get_value('Account',
|
||||||
{'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name')
|
{'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name')
|
||||||
account = create_account(account_name=warehouse_name, \
|
account = create_account(account_name=warehouse_name, \
|
||||||
account_type="Stock", parent_account= parent_account, company=warehouse_obj.company)
|
account_type="Stock", parent_account= parent_account, company=warehouse_obj.company)
|
@ -36,6 +36,7 @@ def get_item_details(args):
|
|||||||
"is_subcontracted": "Yes" / "No",
|
"is_subcontracted": "Yes" / "No",
|
||||||
"ignore_pricing_rule": 0/1
|
"ignore_pricing_rule": 0/1
|
||||||
"project": ""
|
"project": ""
|
||||||
|
"set_warehouse": ""
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
args = process_args(args)
|
args = process_args(args)
|
||||||
@ -189,7 +190,6 @@ def get_basic_details(args, item):
|
|||||||
"project": "",
|
"project": "",
|
||||||
barcode: "",
|
barcode: "",
|
||||||
serial_no: "",
|
serial_no: "",
|
||||||
warehouse: "",
|
|
||||||
currency: "",
|
currency: "",
|
||||||
update_stock: "",
|
update_stock: "",
|
||||||
price_list: "",
|
price_list: "",
|
||||||
@ -219,7 +219,7 @@ def get_basic_details(args, item):
|
|||||||
item_defaults = get_item_defaults(item.name, args.company)
|
item_defaults = get_item_defaults(item.name, args.company)
|
||||||
item_group_defaults = get_item_group_defaults(item.name, args.company)
|
item_group_defaults = get_item_group_defaults(item.name, args.company)
|
||||||
|
|
||||||
warehouse = user_default_warehouse or item_defaults.get("default_warehouse") or\
|
warehouse = args.get("set_warehouse") or user_default_warehouse or item_defaults.get("default_warehouse") or\
|
||||||
item_group_defaults.get("default_warehouse") or args.warehouse
|
item_group_defaults.get("default_warehouse") or args.warehouse
|
||||||
|
|
||||||
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
if args.get('doctype') == "Material Request" and not args.get('material_request_type'):
|
||||||
@ -273,7 +273,7 @@ def get_basic_details(args, item):
|
|||||||
"transaction_date": args.get("transaction_date")
|
"transaction_date": args.get("transaction_date")
|
||||||
})
|
})
|
||||||
|
|
||||||
if item.enable_deferred_revenue:
|
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
||||||
out.update(calculate_service_end_date(args, item))
|
out.update(calculate_service_end_date(args, item))
|
||||||
|
|
||||||
# calculate conversion factor
|
# calculate conversion factor
|
||||||
@ -310,9 +310,15 @@ def calculate_service_end_date(args, item=None):
|
|||||||
if not item:
|
if not item:
|
||||||
item = frappe.get_cached_doc("Item", args.item_code)
|
item = frappe.get_cached_doc("Item", args.item_code)
|
||||||
|
|
||||||
enable_deferred = "enable_deferred_revenue" if args.doctype=="Sales Invoice" else "enable_deferred_expense"
|
doctype = args.get("parenttype") or args.get("doctype")
|
||||||
no_of_months = "no_of_months" if args.doctype=="Sales Invoice" else "no_of_months_exp"
|
if doctype == "Sales Invoice":
|
||||||
account = "deferred_revenue_account" if args.doctype=="Sales Invoice" else "deferred_expense_account"
|
enable_deferred = "enable_deferred_revenue"
|
||||||
|
no_of_months = "no_of_months"
|
||||||
|
account = "deferred_revenue_account"
|
||||||
|
else:
|
||||||
|
enable_deferred = "enable_deferred_expense"
|
||||||
|
no_of_months = "no_of_months_exp"
|
||||||
|
account = "deferred_expense_account"
|
||||||
|
|
||||||
service_start_date = args.service_start_date if args.service_start_date else args.transaction_date
|
service_start_date = args.service_start_date if args.service_start_date else args.transaction_date
|
||||||
service_end_date = add_months(service_start_date, item.get(no_of_months))
|
service_end_date = add_months(service_start_date, item.get(no_of_months))
|
||||||
@ -336,7 +342,7 @@ def get_default_expense_account(args, item, item_group):
|
|||||||
or args.expense_account)
|
or args.expense_account)
|
||||||
|
|
||||||
def get_default_deferred_account(args, item, fieldname=None):
|
def get_default_deferred_account(args, item, fieldname=None):
|
||||||
if item.enable_deferred_revenue:
|
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
||||||
return (item.get(fieldname)
|
return (item.get(fieldname)
|
||||||
or args.get(fieldname)
|
or args.get(fieldname)
|
||||||
or frappe.get_cached_value('Company', args.company, "default_"+fieldname))
|
or frappe.get_cached_value('Company', args.company, "default_"+fieldname))
|
||||||
@ -370,16 +376,16 @@ def get_price_list_rate(args, item_doc, out):
|
|||||||
|
|
||||||
price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
|
price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
|
||||||
|
|
||||||
|
# variant
|
||||||
|
if not price_list_rate and item_doc.variant_of:
|
||||||
|
price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
|
||||||
|
|
||||||
# insert in database
|
# insert in database
|
||||||
if not price_list_rate:
|
if not price_list_rate:
|
||||||
if args.price_list and args.rate:
|
if args.price_list and args.rate:
|
||||||
insert_item_price(args)
|
insert_item_price(args)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# variant
|
|
||||||
if not price_list_rate and item_doc.variant_of:
|
|
||||||
price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
|
|
||||||
|
|
||||||
out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
|
out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
|
||||||
/ flt(args.conversion_rate)
|
/ flt(args.conversion_rate)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user