Fixed merge conflict
This commit is contained in:
commit
d855167b9b
@ -2,7 +2,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
__version__ = '7.1.15'
|
||||
__version__ = '7.1.16'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -28,6 +28,7 @@ frappe.ui.form.on('Asset', {
|
||||
refresh: function(frm) {
|
||||
frappe.ui.form.trigger("Asset", "is_existing_asset");
|
||||
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
|
||||
frm.events.make_schedules_editable(frm);
|
||||
|
||||
if (frm.doc.docstatus==1) {
|
||||
if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) {
|
||||
@ -141,6 +142,22 @@ frappe.ui.form.on('Asset', {
|
||||
frm.toggle_enable("supplier", frm.doc.is_existing_asset);
|
||||
frm.toggle_reqd("next_depreciation_date", !frm.doc.is_existing_asset);
|
||||
},
|
||||
|
||||
opening_accumulated_depreciation: function(frm) {
|
||||
erpnext.asset.set_accululated_depreciation(frm);
|
||||
},
|
||||
|
||||
depreciation_method: function(frm) {
|
||||
frm.events.make_schedules_editable(frm);
|
||||
},
|
||||
|
||||
make_schedules_editable: function(frm) {
|
||||
var is_editable = frm.doc.depreciation_method==="Manual" ? true : false;
|
||||
frm.toggle_enable("schedules", is_editable);
|
||||
frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
|
||||
frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Depreciation Schedule', {
|
||||
@ -159,9 +176,25 @@ frappe.ui.form.on('Depreciation Schedule', {
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
depreciation_amount: function(frm, cdt, cdn) {
|
||||
erpnext.asset.set_accululated_depreciation(frm);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
erpnext.asset.set_accululated_depreciation = function(frm) {
|
||||
if(frm.doc.depreciation_method != "Manual") return;
|
||||
|
||||
accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
|
||||
$.each(frm.doc.schedules || [], function(i, row) {
|
||||
accumulated_depreciation += flt(row.depreciation_amount);
|
||||
frappe.model.set_value(row.doctype, row.name,
|
||||
"accumulated_depreciation_amount", accumulated_depreciation);
|
||||
})
|
||||
}
|
||||
|
||||
erpnext.asset.make_purchase_invoice = function(frm) {
|
||||
frappe.call({
|
||||
args: {
|
||||
|
@ -534,7 +534,7 @@
|
||||
"columns": 0,
|
||||
"fieldname": "value_after_depreciation",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
@ -601,7 +601,7 @@
|
||||
"label": "Depreciation Method",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nStraight Line\nDouble Declining Balance",
|
||||
"options": "\nStraight Line\nDouble Declining Balance\nManual",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -777,7 +777,7 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
@ -825,7 +825,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-07 05:48:01.360878",
|
||||
"modified": "2016-11-18 15:59:19.774500",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Asset",
|
||||
|
@ -18,6 +18,7 @@ class Asset(Document):
|
||||
self.set_missing_values()
|
||||
self.validate_asset_values()
|
||||
self.make_depreciation_schedule()
|
||||
self.set_accumulated_depreciation()
|
||||
self.validate_expected_value_after_useful_life()
|
||||
# Validate depreciation related accounts
|
||||
get_depreciation_accounts(self)
|
||||
@ -87,9 +88,10 @@ class Asset(Document):
|
||||
frappe.throw(_("Please set Next Depreciation Date"))
|
||||
|
||||
def make_depreciation_schedule(self):
|
||||
self.schedules = []
|
||||
if self.depreciation_method != 'Manual':
|
||||
self.schedules = []
|
||||
|
||||
if not self.get("schedules") and self.next_depreciation_date:
|
||||
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
|
||||
value_after_depreciation = flt(self.value_after_depreciation)
|
||||
|
||||
number_of_pending_depreciations = cint(self.total_number_of_depreciations) - \
|
||||
@ -100,18 +102,21 @@ class Asset(Document):
|
||||
n * cint(self.frequency_of_depreciation))
|
||||
|
||||
depreciation_amount = self.get_depreciation_amount(value_after_depreciation)
|
||||
|
||||
accumulated_depreciation += flt(depreciation_amount)
|
||||
value_after_depreciation -= flt(depreciation_amount)
|
||||
|
||||
self.append("schedules", {
|
||||
"schedule_date": schedule_date,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"accumulated_depreciation_amount": accumulated_depreciation
|
||||
"depreciation_amount": depreciation_amount
|
||||
})
|
||||
|
||||
def set_accumulated_depreciation(self):
|
||||
accumulated_depreciation = flt(self.opening_accumulated_depreciation)
|
||||
for d in self.get("schedules"):
|
||||
accumulated_depreciation += flt(d.depreciation_amount)
|
||||
d.accumulated_depreciation_amount = accumulated_depreciation
|
||||
|
||||
def get_depreciation_amount(self, depreciable_value):
|
||||
if self.depreciation_method == "Straight Line":
|
||||
if self.depreciation_method in ("Straight Line", "Manual"):
|
||||
depreciation_amount = (flt(self.value_after_depreciation) -
|
||||
flt(self.expected_value_after_useful_life)) / (cint(self.total_number_of_depreciations) -
|
||||
cint(self.number_of_depreciations_booked))
|
||||
@ -126,16 +131,15 @@ class Asset(Document):
|
||||
return depreciation_amount
|
||||
|
||||
def validate_expected_value_after_useful_life(self):
|
||||
if self.depreciation_method == "Double Declining Balance":
|
||||
accumulated_depreciation_after_full_schedule = \
|
||||
max([d.accumulated_depreciation_amount for d in self.get("schedules")])
|
||||
accumulated_depreciation_after_full_schedule = \
|
||||
max([d.accumulated_depreciation_amount for d in self.get("schedules")])
|
||||
|
||||
asset_value_after_full_schedule = (flt(self.gross_purchase_amount) -
|
||||
flt(accumulated_depreciation_after_full_schedule))
|
||||
asset_value_after_full_schedule = (flt(self.gross_purchase_amount) -
|
||||
flt(accumulated_depreciation_after_full_schedule))
|
||||
|
||||
if self.expected_value_after_useful_life < asset_value_after_full_schedule:
|
||||
frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")
|
||||
.format(asset_value_after_full_schedule))
|
||||
if self.expected_value_after_useful_life < asset_value_after_full_schedule:
|
||||
frappe.throw(_("Expected value after useful life must be greater than or equal to {0}")
|
||||
.format(asset_value_after_full_schedule))
|
||||
|
||||
def validate_cancellation(self):
|
||||
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
|
||||
|
@ -120,6 +120,30 @@ class TestAsset(unittest.TestCase):
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
def test_schedule_for_manual_method(self):
|
||||
asset = frappe.get_doc("Asset", "Macbook Pro 1")
|
||||
asset.depreciation_method = "Manual"
|
||||
asset.schedules = []
|
||||
for schedule_date, amount in [["2020-12-31", 40000], ["2021-06-30", 30000], ["2021-10-31", 20000]]:
|
||||
asset.append("schedules", {
|
||||
"schedule_date": schedule_date,
|
||||
"depreciation_amount": amount
|
||||
})
|
||||
asset.save()
|
||||
|
||||
self.assertEqual(asset.status, "Draft")
|
||||
|
||||
expected_schedules = [
|
||||
["2020-12-31", 40000, 40000],
|
||||
["2021-06-30", 30000, 70000],
|
||||
["2021-10-31", 20000, 90000]
|
||||
]
|
||||
|
||||
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
|
||||
for d in asset.get("schedules")]
|
||||
|
||||
self.assertEqual(schedules, expected_schedules)
|
||||
|
||||
def test_depreciation(self):
|
||||
asset = frappe.get_doc("Asset", "Macbook Pro 1")
|
||||
asset.submit()
|
||||
|
@ -46,6 +46,12 @@ frappe.ui.form.on("Bank Reconciliation", {
|
||||
callback: function(r, rt) {
|
||||
frm.refresh_field("payment_entries");
|
||||
frm.refresh_fields();
|
||||
|
||||
$(frm.fields_dict.payment_entries.wrapper).find("[data-fieldname=amount]").each(function(i,v){
|
||||
if (i !=0){
|
||||
$(v).addClass("text-right")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, getdate, nowdate
|
||||
from frappe.utils import flt, getdate, nowdate, fmt_money
|
||||
from frappe import msgprint, _
|
||||
from frappe.model.document import Document
|
||||
|
||||
@ -26,8 +26,8 @@ class BankReconciliation(Document):
|
||||
select
|
||||
"Journal Entry" as payment_document, t1.name as payment_entry,
|
||||
t1.cheque_no as cheque_number, t1.cheque_date,
|
||||
abs(t2.debit_in_account_currency - t2.credit_in_account_currency) as amount,
|
||||
t1.posting_date, t2.against_account, t1.clearance_date
|
||||
t2.debit_in_account_currency as debit, t2.credit_in_account_currency as credit,
|
||||
t1.posting_date, t2.against_account, t1.clearance_date, t2.account_currency
|
||||
from
|
||||
`tabJournal Entry` t1, `tabJournal Entry Account` t2
|
||||
where
|
||||
@ -41,16 +41,18 @@ class BankReconciliation(Document):
|
||||
select
|
||||
"Payment Entry" as payment_document, name as payment_entry,
|
||||
reference_no as cheque_number, reference_date as cheque_date,
|
||||
if(paid_from=%s, paid_amount, received_amount) as amount,
|
||||
posting_date, party as against_account, clearance_date
|
||||
if(paid_from=%(account)s, paid_amount, "") as credit,
|
||||
if(paid_from=%(account)s, "", received_amount) as debit,
|
||||
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
|
||||
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
|
||||
from `tabPayment Entry`
|
||||
where
|
||||
(paid_from=%s or paid_to=%s) and docstatus=1
|
||||
and posting_date >= %s and posting_date <= %s {0}
|
||||
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
|
||||
and posting_date >= %(from)s and posting_date <= %(to)s {0}
|
||||
order by
|
||||
posting_date ASC, name DESC
|
||||
""".format(condition),
|
||||
(self.bank_account, self.bank_account, self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
{"account":self.bank_account, "from":self.from_date, "to":self.to_date}, as_dict=1)
|
||||
|
||||
entries = sorted(list(payment_entries)+list(journal_entries),
|
||||
key=lambda k: k['posting_date'] or getdate(nowdate()))
|
||||
@ -60,6 +62,11 @@ class BankReconciliation(Document):
|
||||
|
||||
for d in entries:
|
||||
row = self.append('payment_entries', {})
|
||||
|
||||
d.amount = fmt_money(d.debit if d.debit else d.credit, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
|
||||
d.pop("credit")
|
||||
d.pop("debit")
|
||||
d.pop("account_currency")
|
||||
row.update(d)
|
||||
self.total_amount += flt(d.amount)
|
||||
|
||||
|
@ -40,14 +40,14 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"columns": 1,
|
||||
"fieldname": "payment_entry",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Payment Entry",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
@ -69,7 +69,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"columns": 2,
|
||||
"fieldname": "against_account",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -99,7 +99,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@ -110,7 +110,7 @@
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "debit",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "account_currency",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
@ -151,7 +151,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -178,7 +178,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"columns": 1,
|
||||
"fieldname": "cheque_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
@ -267,7 +267,7 @@
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2016-08-26 01:51:36.123941",
|
||||
"modified": "2016-11-17 11:39:00.308624",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Reconciliation Detail",
|
||||
|
@ -10,11 +10,13 @@
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
@ -29,7 +31,8 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@ -40,6 +43,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "depreciation_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -55,7 +59,8 @@
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
@ -66,6 +71,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
@ -80,6 +86,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -90,6 +97,7 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "accumulated_depreciation_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
@ -106,8 +114,9 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
@ -116,6 +125,8 @@
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"fieldname": "journal_entry",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -132,6 +143,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -142,7 +154,8 @@
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"depends_on": "eval:(!doc.journal_entry && doc.schedule_date <= get_today())",
|
||||
"columns": 0,
|
||||
"depends_on": "eval:(doc.docstatus==1 && !doc.journal_entry && doc.schedule_date <= get_today())",
|
||||
"fieldname": "make_depreciation_entry",
|
||||
"fieldtype": "Button",
|
||||
"hidden": 0,
|
||||
@ -158,6 +171,7 @@
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
@ -175,7 +189,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-07-11 03:27:59.603924",
|
||||
"modified": "2016-11-18 16:42:19.543657",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Depreciation Schedule",
|
||||
|
@ -114,7 +114,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-07 05:30:20.409675",
|
||||
"modified": "2016-11-21 14:54:35.998761",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Monthly Distribution",
|
||||
@ -164,7 +164,7 @@
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
|
@ -0,0 +1,66 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-11-16 15:27:16.413449",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Customer Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Customer Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-16 15:27:25.730507",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Customer Group",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class POSCustomerGroup(Document):
|
||||
pass
|
0
erpnext/accounts/doctype/pos_item_group/__init__.py
Normal file
0
erpnext/accounts/doctype/pos_item_group/__init__.py
Normal file
66
erpnext/accounts/doctype/pos_item_group/pos_item_group.json
Normal file
66
erpnext/accounts/doctype/pos_item_group/pos_item_group.json
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-11-16 15:26:47.706713",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Item Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Item Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"in_dialog": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-16 15:27:32.263630",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Item Group",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_seen": 0
|
||||
}
|
10
erpnext/accounts/doctype/pos_item_group/pos_item_group.py
Normal file
10
erpnext/accounts/doctype/pos_item_group/pos_item_group.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class POSItemGroup(Document):
|
||||
pass
|
@ -26,6 +26,30 @@ frappe.ui.form.on("POS Profile", "onload", function(frm) {
|
||||
});
|
||||
});
|
||||
|
||||
frappe.ui.form.on("POS Profile", {
|
||||
setup: function(frm) {
|
||||
frm.trigger("get_query_for_groups")
|
||||
},
|
||||
|
||||
get_query_for_groups: function(frm) {
|
||||
frm.fields_dict['item_groups'].grid.get_field('item_group').get_query = function(frm, cdt, cdn) {
|
||||
return{
|
||||
filters: {
|
||||
'is_group': 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frm.fields_dict['customer_groups'].grid.get_field('customer_group').get_query = function(frm, cdt, cdn) {
|
||||
return{
|
||||
filters: {
|
||||
'is_group': 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Income Account
|
||||
// --------------------------------
|
||||
cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) {
|
||||
|
@ -388,6 +388,114 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_groups",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Item Groups",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "POS Item Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "customer_groups",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Customer Groups",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "POS Customer Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -562,35 +670,6 @@
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Customer Group",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Customer Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
@ -984,7 +1063,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-11-07 05:19:52.335433",
|
||||
"modified": "2016-11-17 05:19:52.335433",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
|
@ -13,6 +13,7 @@ class POSProfile(Document):
|
||||
def validate(self):
|
||||
self.check_for_duplicate()
|
||||
self.validate_all_link_fields()
|
||||
self.validate_duplicate_groups()
|
||||
|
||||
def check_for_duplicate(self):
|
||||
res = frappe.db.sql("""select name, user from `tabPOS Profile`
|
||||
@ -37,6 +38,16 @@ class POSProfile(Document):
|
||||
"company": self.company, "name": link_dn}):
|
||||
frappe.throw(_("{0} does not belong to Company {1}").format(link_dn, self.company))
|
||||
|
||||
def validate_duplicate_groups(self):
|
||||
item_groups = [d.item_group for d in self.item_groups]
|
||||
customer_groups = [d.customer_group for d in self.customer_groups]
|
||||
|
||||
if len(item_groups) != len(set(item_groups)):
|
||||
frappe.throw(_("Duplicate item group found in the item group table"), title = "Duplicate Item Group")
|
||||
|
||||
if len(customer_groups) != len(set(customer_groups)):
|
||||
frappe.throw(_("Duplicate customer group found in the cutomer group table"), title = "Duplicate Customer Group")
|
||||
|
||||
def before_save(self):
|
||||
set_account_for_mode_of_payment(self)
|
||||
|
||||
|
@ -5,8 +5,47 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
# test_records = frappe.get_test_records('POS Profile')
|
||||
from erpnext.stock.get_item_details import get_pos_profile
|
||||
from erpnext.accounts.doctype.sales_invoice.pos import get_items_list, get_customers_list
|
||||
|
||||
class TestPOSProfile(unittest.TestCase):
|
||||
pass
|
||||
def test_pos_profile(self):
|
||||
make_pos_profile()
|
||||
|
||||
pos_profile = get_pos_profile("_Test Company") or {}
|
||||
if pos_profile:
|
||||
doc = frappe.get_doc("POS Profile", pos_profile.get("name"))
|
||||
doc.append('item_groups', {'item_group': '_Test Item Group'})
|
||||
doc.append('customer_groups', {'customer_group': '_Test Customer Group'})
|
||||
doc.save()
|
||||
|
||||
items = get_items_list(doc)
|
||||
customers = get_customers_list(doc)
|
||||
|
||||
products_count = frappe.db.sql(""" select count(name) from tabItem where item_group = '_Test Item Group'""", as_list=1)
|
||||
customers_count = frappe.db.sql(""" select count(name) from tabCustomer where customer_group = '_Test Customer Group'""")
|
||||
|
||||
self.assertEquals(len(items), products_count[0][0])
|
||||
self.assertEquals(len(customers), customers_count[0][0])
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
def make_pos_profile():
|
||||
pos_profile = frappe.get_doc({
|
||||
"company": "_Test Company",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"currency": "INR",
|
||||
"doctype": "POS Profile",
|
||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"income_account": "Sales - _TC",
|
||||
"name": "_Test POS Profile",
|
||||
"naming_series": "_T-POS Profile-",
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"write_off_account": "_Test Write Off - _TC",
|
||||
"write_off_cost_center": "_Test Write Off Cost Center - _TC"
|
||||
})
|
||||
|
||||
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
||||
pos_profile.insert()
|
@ -30,10 +30,16 @@ def get_pos_data():
|
||||
return {
|
||||
'doc': doc,
|
||||
'default_customer': pos_profile.get('customer'),
|
||||
'items': get_items(doc, pos_profile),
|
||||
'customers': get_customers(pos_profile, doc, company_data.default_currency),
|
||||
'pricing_rules': get_pricing_rules(doc),
|
||||
'items': get_items_list(pos_profile),
|
||||
'customers': get_customers_list(pos_profile),
|
||||
'serial_no_data': get_serial_no_data(pos_profile, doc.company),
|
||||
'batch_no_data': get_batch_no_data(),
|
||||
'tax_data': get_item_tax_data(),
|
||||
'price_list_data': get_price_list_data(doc.selling_price_list),
|
||||
'bin_data': get_bin_data(pos_profile),
|
||||
'pricing_rules': get_pricing_rule_data(doc),
|
||||
'print_template': print_template,
|
||||
'pos_profile': pos_profile,
|
||||
'meta': {
|
||||
'invoice': frappe.get_meta('Sales Invoice'),
|
||||
'items': frappe.get_meta('Sales Invoice Item'),
|
||||
@ -104,63 +110,117 @@ def update_tax_table(doc):
|
||||
for tax in taxes:
|
||||
doc.append('taxes', tax)
|
||||
|
||||
def get_items(doc, pos_profile):
|
||||
item_list = []
|
||||
for item in frappe.get_all("Item", fields=["*"], filters={'disabled': 0, 'has_variants': 0, 'is_sales_item': 1}):
|
||||
item_doc = frappe.get_doc('Item', item.name)
|
||||
if item_doc.taxes:
|
||||
item.taxes = json.dumps(dict(([d.tax_type, d.tax_rate] for d in
|
||||
item_doc.get("taxes"))))
|
||||
def get_items_list(pos_profile):
|
||||
cond = "1=1"
|
||||
item_groups = []
|
||||
if pos_profile.get('item_groups'):
|
||||
# Get items based on the item groups defined in the POS profile
|
||||
|
||||
item.price_list_rate = frappe.db.get_value('Item Price', {'item_code': item.name,
|
||||
'price_list': doc.selling_price_list}, 'price_list_rate') or 0
|
||||
item.default_warehouse = pos_profile.get('warehouse') or \
|
||||
get_item_warehouse_for_company(doc.company, item.default_warehouse) or None
|
||||
item.expense_account = pos_profile.get('expense_account') or item.expense_account
|
||||
item.income_account = pos_profile.get('income_account') or item_doc.income_account
|
||||
item.cost_center = pos_profile.get('cost_center') or item_doc.selling_cost_center
|
||||
item.actual_qty = frappe.db.get_value('Bin', {'item_code': item.name,
|
||||
'warehouse': item.default_warehouse}, 'actual_qty') or 0
|
||||
item.serial_nos = get_serial_nos(item, pos_profile, doc.company)
|
||||
item.batch_nos = frappe.db.sql_list("""select name from `tabBatch` where ifnull(expiry_date, '4000-10-10') > curdate()
|
||||
and item = %(item_code)s""", {'item_code': item.item_code})
|
||||
cond = "item_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('item_groups'))))
|
||||
item_groups = [d.item_group for d in pos_profile.get('item_groups')]
|
||||
|
||||
item_list.append(item)
|
||||
return frappe.db.sql("""
|
||||
select
|
||||
name, item_code, item_name, description, item_group, expense_account, has_batch_no,
|
||||
has_serial_no, expense_account, selling_cost_center, stock_uom, image,
|
||||
default_warehouse, is_stock_item
|
||||
from
|
||||
tabItem
|
||||
where
|
||||
disabled = 0 and has_variants = 0 and is_sales_item = 1 and {cond}
|
||||
""".format(cond=cond), tuple(item_groups), as_dict=1)
|
||||
|
||||
return item_list
|
||||
def get_customers_list(pos_profile):
|
||||
cond = "1=1"
|
||||
customer_groups = []
|
||||
if pos_profile.get('customer_groups'):
|
||||
# Get customers based on the customer groups defined in the POS profile
|
||||
|
||||
def get_item_warehouse_for_company(company, warehouse):
|
||||
if frappe.db.get_value('Warehouse', warehouse, 'company') != company:
|
||||
warehouse = None
|
||||
return warehouse
|
||||
cond = "customer_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('customer_groups'))))
|
||||
customer_groups = [d.customer_group for d in pos_profile.get('customer_groups')]
|
||||
|
||||
return frappe.db.sql(""" select name, customer_name, customer_group,
|
||||
territory from tabCustomer where disabled = 0
|
||||
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
|
||||
|
||||
def get_serial_no_data(pos_profile, company):
|
||||
# get itemwise serial no data
|
||||
# example {'Nokia Lumia 1020': {'SN0001': 'Pune'}}
|
||||
# where Nokia Lumia 1020 is item code, SN0001 is serial no and Pune is warehouse
|
||||
|
||||
def get_serial_nos(item, pos_profile, company):
|
||||
cond = "1=1"
|
||||
if pos_profile.get('update_stock') and pos_profile.get('warehouse'):
|
||||
cond = "warehouse = '{0}'".format(pos_profile.get('warehouse'))
|
||||
|
||||
serial_nos = frappe.db.sql("""select name, warehouse from `tabSerial No` where {0}
|
||||
and item_code = %(item_code)s and company = %(company)s
|
||||
""".format(cond), {'item_code': item.item_code, 'company': company}, as_dict=1)
|
||||
serial_nos = frappe.db.sql("""select name, warehouse, item_code from `tabSerial No` where {0}
|
||||
and company = %(company)s """.format(cond), {'company': company}, as_dict=1)
|
||||
|
||||
serial_no_list = {}
|
||||
for serial_no in serial_nos:
|
||||
serial_no_list[serial_no.name] = serial_no.warehouse
|
||||
itemwise_serial_no = {}
|
||||
for sn in serial_nos:
|
||||
if sn.item_code not in itemwise_serial_no:
|
||||
itemwise_serial_no.setdefault(sn.item_code, {})
|
||||
itemwise_serial_no[sn.item_code][sn.name] = sn.warehouse
|
||||
|
||||
return serial_no_list
|
||||
return itemwise_serial_no
|
||||
|
||||
def get_customers(pos_profile, doc, company_currency):
|
||||
filters = {'disabled': 0}
|
||||
customer_list = []
|
||||
customers = frappe.get_all("Customer", fields=["*"], filters = filters)
|
||||
def get_batch_no_data():
|
||||
# get itemwise batch no data
|
||||
# exmaple: {'LED-GRE': [Batch001, Batch002]}
|
||||
# where LED-GRE is item code, SN0001 is serial no and Pune is warehouse
|
||||
|
||||
for customer in customers:
|
||||
customer_currency = get_party_account_currency('Customer', customer.name, doc.company) or doc.currency
|
||||
if customer_currency == doc.currency or customer_currency == company_currency:
|
||||
customer_list.append(customer)
|
||||
return customer_list
|
||||
itemwise_batch = {}
|
||||
batches = frappe.db.sql("""select name, item from `tabBatch`
|
||||
where ifnull(expiry_date, '4000-10-10') >= curdate()""", as_dict=1)
|
||||
|
||||
def get_pricing_rules(doc):
|
||||
for batch in batches:
|
||||
if batch.item not in itemwise_batch:
|
||||
itemwise_batch.setdefault(batch.item, [])
|
||||
itemwise_batch[batch.item].append(batch.name)
|
||||
|
||||
return itemwise_batch
|
||||
|
||||
def get_item_tax_data():
|
||||
# get default tax of an item
|
||||
# example: {'Consulting Services': {'Excise 12 - TS': '12.000'}}
|
||||
|
||||
itemwise_tax = {}
|
||||
taxes = frappe.db.sql(""" select parent, tax_type, tax_rate from `tabItem Tax`""", as_dict=1)
|
||||
|
||||
for tax in taxes:
|
||||
if tax.parent not in itemwise_tax:
|
||||
itemwise_tax.setdefault(tax.parent, {})
|
||||
itemwise_tax[tax.parent][tax.tax_type] = tax.tax_rate
|
||||
|
||||
return itemwise_tax
|
||||
|
||||
def get_price_list_data(selling_price_list):
|
||||
itemwise_price_list = {}
|
||||
price_lists = frappe.db.sql("""Select ifnull(price_list_rate, 0) as price_list_rate,
|
||||
item_code from `tabItem Price` ip where price_list = %(price_list)s""",
|
||||
{'price_list': selling_price_list}, as_dict=1)
|
||||
|
||||
for item in price_lists:
|
||||
itemwise_price_list[item.item_code] = item.price_list_rate
|
||||
|
||||
return itemwise_price_list
|
||||
|
||||
def get_bin_data(pos_profile):
|
||||
itemwise_bin_data = {}
|
||||
cond = "1=1"
|
||||
if pos_profile.get('warehouse'):
|
||||
cond = "warehouse = '{0}'".format(pos_profile.get('warehouse'))
|
||||
|
||||
bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin`
|
||||
where actual_qty > 0 and {cond}""".format(cond=cond), as_dict=1)
|
||||
|
||||
for bins in bin_data:
|
||||
if bins.item_code not in itemwise_bin_data:
|
||||
itemwise_bin_data.setdefault(bins.item_code, {})
|
||||
itemwise_bin_data[bins.item_code][bins.warehouse] = bins.actual_qty
|
||||
|
||||
return itemwise_bin_data
|
||||
|
||||
def get_pricing_rule_data(doc):
|
||||
pricing_rules = ""
|
||||
if doc.ignore_pricing_rule == 0:
|
||||
pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2
|
||||
|
@ -20,6 +20,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
erpnext.queries.setup_queries(this.frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(me.frm.doc);
|
||||
});
|
||||
|
||||
if(this.frm.doc.__islocal && this.frm.doc.is_pos) {
|
||||
//Load pos profile data on the invoice if the default value of Is POS is 1
|
||||
|
||||
me.frm.script_manager.trigger("is_pos");
|
||||
me.frm.refresh_fields();
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(doc, dt, dn) {
|
||||
|
@ -7,6 +7,7 @@ import unittest, copy
|
||||
from frappe.utils import nowdate, add_days, flt, nowdate
|
||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
|
||||
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
|
||||
from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency
|
||||
from erpnext.stock.doctype.serial_no.serial_no import SerialNoWarehouseError
|
||||
@ -467,7 +468,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
def test_pos_gl_entry_with_perpetual_inventory(self):
|
||||
set_perpetual_inventory()
|
||||
self.make_pos_profile()
|
||||
make_pos_profile()
|
||||
|
||||
self._insert_purchase_receipt()
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
@ -486,7 +487,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
def test_pos_change_amount(self):
|
||||
set_perpetual_inventory()
|
||||
self.make_pos_profile()
|
||||
make_pos_profile()
|
||||
|
||||
self._insert_purchase_receipt()
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
@ -508,7 +509,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
set_perpetual_inventory()
|
||||
|
||||
self.make_pos_profile()
|
||||
make_pos_profile()
|
||||
self._insert_purchase_receipt()
|
||||
|
||||
pos = copy.deepcopy(test_records[1])
|
||||
@ -572,26 +573,6 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
def make_pos_profile(self):
|
||||
pos_profile = frappe.get_doc({
|
||||
"company": "_Test Company",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"currency": "INR",
|
||||
"doctype": "POS Profile",
|
||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"income_account": "Sales - _TC",
|
||||
"name": "_Test POS Profile",
|
||||
"naming_series": "_T-POS Profile-",
|
||||
"selling_price_list": "_Test Price List",
|
||||
"territory": "_Test Territory",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"write_off_account": "_Test Write Off - _TC",
|
||||
"write_off_cost_center": "_Test Write Off Cost Center - _TC"
|
||||
})
|
||||
|
||||
if not frappe.db.exists("POS Profile", "_Test POS Profile"):
|
||||
pos_profile.insert()
|
||||
|
||||
def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
|
@ -25,7 +25,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.set_indicator();
|
||||
this.onload();
|
||||
this.make_menu_list();
|
||||
this.set_interval_for_si_sync();
|
||||
this.si_docs = this.get_doc_from_localstorage();
|
||||
},
|
||||
|
||||
@ -73,8 +72,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.get_data_from_server(function(){
|
||||
me.create_new();
|
||||
});
|
||||
|
||||
this.check_internet_connection();
|
||||
},
|
||||
|
||||
make_menu_list: function(){
|
||||
@ -204,13 +201,10 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
freeze: true,
|
||||
freeze_message: __("Master data syncing, it might take some time"),
|
||||
callback: function(r){
|
||||
window.items = r.message.items;
|
||||
window.customers = r.message.customers;
|
||||
window.pricing_rules = r.message.pricing_rules;
|
||||
window.meta = r.message.meta;
|
||||
window.print_template = r.message.print_template;
|
||||
me.default_customer = r.message.default_customer || null;
|
||||
me.init_master_data(r)
|
||||
localStorage.setItem('doc', JSON.stringify(r.message.doc));
|
||||
me.set_interval_for_si_sync();
|
||||
me.check_internet_connection();
|
||||
if(callback){
|
||||
callback();
|
||||
}
|
||||
@ -218,6 +212,22 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
})
|
||||
},
|
||||
|
||||
init_master_data: function(r){
|
||||
var me = this;
|
||||
this.meta = r.message.meta;
|
||||
this.item_data = r.message.items;
|
||||
this.customers = r.message.customers;
|
||||
this.serial_no_data = r.message.serial_no_data;
|
||||
this.batch_no_data = r.message.batch_no_data;
|
||||
this.tax_data = r.message.tax_data;
|
||||
this.price_list_data = r.message.price_list_data;
|
||||
this.bin_data = r.message.bin_data;
|
||||
this.pricing_rules = r.message.pricing_rules;
|
||||
this.print_template = r.message.print_template;
|
||||
this.pos_profile_data = r.message.pos_profile;
|
||||
this.default_customer = r.message.default_customer || null;
|
||||
},
|
||||
|
||||
save_previous_entry : function(){
|
||||
if(this.frm.doc.items.length > 0){
|
||||
this.create_invoice()
|
||||
@ -233,20 +243,19 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
|
||||
load_data: function(load_doc){
|
||||
this.items = window.items;
|
||||
this.customers = window.customers;
|
||||
this.pricing_rules = window.pricing_rules;
|
||||
var me = this;
|
||||
|
||||
this.items = this.item_data;
|
||||
if(load_doc) {
|
||||
this.frm.doc = JSON.parse(localStorage.getItem('doc'));
|
||||
}
|
||||
|
||||
$.each(window.meta, function(i, data){
|
||||
$.each(this.meta, function(i, data){
|
||||
frappe.meta.sync(data)
|
||||
})
|
||||
|
||||
this.print_template = frappe.render_template("print_template",
|
||||
{content: window.print_template, title:"POS",
|
||||
{content: this.print_template, title:"POS",
|
||||
base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css})
|
||||
},
|
||||
|
||||
@ -387,12 +396,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
var $wrap = me.wrapper.find(".item-list");
|
||||
me.wrapper.find(".item-list").empty();
|
||||
|
||||
if (this.items) {
|
||||
if (this.items.length > 0) {
|
||||
$.each(this.items, function(index, obj) {
|
||||
if(index < 30){
|
||||
$(frappe.render_template("pos_item", {
|
||||
item_code: obj.name,
|
||||
item_price: format_currency(obj.price_list_rate, me.frm.doc.currency),
|
||||
item_price: format_currency(me.price_list_data[obj.name], me.frm.doc.currency),
|
||||
item_name: obj.name===obj.item_name ? "" : obj.item_name,
|
||||
item_image: obj.image ? "url('" + obj.image + "')" : null,
|
||||
color: frappe.get_palette(obj.item_name),
|
||||
@ -400,6 +409,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
})).tooltip().appendTo($wrap);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("<h4>Searching record not found.</h4>").appendTo($wrap)
|
||||
}
|
||||
|
||||
if(this.items.length == 1
|
||||
@ -426,7 +437,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.item_batch_no = {};
|
||||
|
||||
if(item_code){
|
||||
return $.grep(window.items, function(item){
|
||||
return $.grep(this.item_data, function(item){
|
||||
if(item.item_code == item_code ){
|
||||
return true
|
||||
}
|
||||
@ -439,14 +450,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
search_status = true
|
||||
|
||||
if(key){
|
||||
return $.grep(window.items, function(item){
|
||||
return $.grep(this.item_data, function(item){
|
||||
if(search_status){
|
||||
if(in_list(item.batch_nos, me.search.$input.val())){
|
||||
if(in_list(me.batch_no_data[item.item_code], me.search.$input.val())){
|
||||
search_status = false;
|
||||
return me.item_batch_no[item.item_code] = me.search.$input.val()
|
||||
} else if(in_list(Object.keys(item.serial_nos), me.search.$input.val())) {
|
||||
} else if( me.serial_no_data[item.item_code]
|
||||
&& in_list(Object.keys(me.serial_no_data[item.item_code]), me.search.$input.val())) {
|
||||
search_status = false;
|
||||
me.item_serial_no[item.item_code] = [me.search.$input.val(), item.serial_nos[me.search.$input.val()]]
|
||||
me.item_serial_no[item.item_code] = [me.search.$input.val(), me.serial_no_data[item.item_code][me.search.$input.val()]]
|
||||
return true
|
||||
} else if(item.barcode == me.search.$input.val()) {
|
||||
search_status = false;
|
||||
@ -458,7 +470,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
})
|
||||
}else{
|
||||
return window.items;
|
||||
return this.item_data;
|
||||
}
|
||||
},
|
||||
|
||||
@ -611,18 +623,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.child.description = this.items[0].description;
|
||||
this.child.qty = 1;
|
||||
this.child.item_group = this.items[0].item_group;
|
||||
this.child.cost_center = this.items[0].cost_center;
|
||||
this.child.income_account = this.items[0].income_account;
|
||||
this.child.cost_center = this.pos_profile_data['cost_center'] || this.items[0].cost_center;
|
||||
this.child.income_account = this.pos_profile_data['income_account'] || this.items[0].income_account;
|
||||
this.child.warehouse = (this.item_serial_no[this.child.item_code]
|
||||
? this.item_serial_no[this.child.item_code][1] : this.items[0].default_warehouse);
|
||||
this.child.price_list_rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.rate = flt(this.items[0].price_list_rate, 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.actual_qty = this.items[0].actual_qty;
|
||||
? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse) );
|
||||
this.child.price_list_rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.actual_qty = me.get_actual_qty(this.items[0]);
|
||||
this.child.amount = flt(this.child.qty) * flt(this.child.rate);
|
||||
this.child.batch_no = this.item_batch_no[this.child.item_code];
|
||||
this.child.serial_no = (this.item_serial_no[this.child.item_code]
|
||||
? this.item_serial_no[this.child.item_code][0] : '');
|
||||
this.child.item_tax_rate = this.items[0].taxes;
|
||||
this.child.item_tax_rate = JSON.stringify(this.tax_data[this.child.item_code]);
|
||||
},
|
||||
|
||||
update_paid_amount_status: function(update_paid_amount){
|
||||
@ -668,7 +680,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
item_code: d.item_code,
|
||||
item_name: (d.item_name===d.item_code || !d.item_name) ? "" : ("<br>" + d.item_name),
|
||||
qty: d.qty,
|
||||
actual_qty: d.actual_qty,
|
||||
actual_qty: me.actual_qty,
|
||||
projected_qty: d.projected_qty,
|
||||
rate: format_number(d.rate, me.frm.doc.currency),
|
||||
amount: format_currency(d.amount, me.frm.doc.currency)
|
||||
@ -1064,8 +1076,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
},
|
||||
|
||||
validate_warehouse: function(){
|
||||
if(!this.items[0].default_warehouse){
|
||||
if(this.items[0].is_stock_item && !this.items[0].default_warehouse && !this.pos_profile_data['warehouse']){
|
||||
frappe.throw(__("Default warehouse is required for selected item"))
|
||||
}
|
||||
},
|
||||
|
||||
get_actual_qty: function(item) {
|
||||
this.actual_qty = 0.0;
|
||||
var warehouse = this.pos_profile_data['warehouse'] || item.default_warehouse;
|
||||
if(warehouse && this.bin_data[item.item_code]) {
|
||||
this.actual_qty = this.bin_data[item.item_code][warehouse] || 0;
|
||||
}
|
||||
|
||||
return this.actual_qty
|
||||
}
|
||||
})
|
@ -14,10 +14,10 @@ def execute(filters=None):
|
||||
liability = get_data(filters.company, "Liability", "Credit", period_list, only_current_fiscal_year=False)
|
||||
equity = get_data(filters.company, "Equity", "Credit", period_list, only_current_fiscal_year=False)
|
||||
|
||||
provisional_profit_loss,total_credit = get_provisional_profit_loss(asset, liability, equity,
|
||||
provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,
|
||||
period_list, filters.company)
|
||||
|
||||
message,opening_balance = check_opening_balance(asset, liability, equity)
|
||||
message, opening_balance = check_opening_balance(asset, liability, equity)
|
||||
|
||||
data = []
|
||||
data.extend(asset or [])
|
||||
@ -32,7 +32,9 @@ def execute(filters=None):
|
||||
}
|
||||
for period in period_list:
|
||||
unclosed[period.key] = opening_balance
|
||||
provisional_profit_loss[period.key] = provisional_profit_loss[period.key] - opening_balance
|
||||
if provisional_profit_loss:
|
||||
provisional_profit_loss[period.key] = provisional_profit_loss[period.key] - opening_balance
|
||||
|
||||
unclosed["total"]=opening_balance
|
||||
data.append(unclosed)
|
||||
|
||||
@ -48,15 +50,11 @@ def execute(filters=None):
|
||||
return columns, data, message, chart
|
||||
|
||||
def get_provisional_profit_loss(asset, liability, equity, period_list, company):
|
||||
provisional_profit_loss = {}
|
||||
total_row = {}
|
||||
if asset and (liability or equity):
|
||||
total = total_row_total=0
|
||||
currency = frappe.db.get_value("Company", company, "default_currency")
|
||||
provisional_profit_loss = {
|
||||
"account_name": "'" + _("Provisional Profit / Loss (Credit)") + "'",
|
||||
"account": None,
|
||||
"warn_if_negative": True,
|
||||
"currency": currency
|
||||
}
|
||||
total_row = {
|
||||
"account_name": "'" + _("Total (Credit)") + "'",
|
||||
"account": None,
|
||||
@ -85,9 +83,14 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company):
|
||||
total_row["total"] = total_row_total
|
||||
|
||||
if has_value:
|
||||
return provisional_profit_loss, total_row
|
||||
return None,total_row
|
||||
return None, None
|
||||
provisional_profit_loss.update({
|
||||
"account_name": "'" + _("Provisional Profit / Loss (Credit)") + "'",
|
||||
"account": None,
|
||||
"warn_if_negative": True,
|
||||
"currency": currency
|
||||
})
|
||||
|
||||
return provisional_profit_loss, total_row
|
||||
|
||||
def check_opening_balance(asset, liability, equity):
|
||||
# Check if previous year balance sheet closed
|
||||
|
@ -8,7 +8,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 15%">{%= __("Posting Date") %}</th>
|
||||
<th style="width: 15%">{%= __("Journal Entry") %}</th>
|
||||
<th style="width: 15%">{%= __("Payment Entry") %}</th>
|
||||
<th style="width: 40%">{%= __("Reference") %}</th>
|
||||
<th style="width: 15%; text-align: right;">{%= __("Debit") %}</th>
|
||||
<th style="width: 15%; text-align: right;">{%= __("Credit") %}</th>
|
||||
@ -19,10 +19,10 @@
|
||||
{% if (data[i]["posting_date"]) { %}
|
||||
<tr>
|
||||
<td>{%= dateutil.str_to_user(data[i]["posting_date"]) %}</td>
|
||||
<td>{%= data[i]["journal_entry"] %}</td>
|
||||
<td>{%= data[i]["payment_entry"] %}</td>
|
||||
<td>{%= __("Against") %}: {%= data[i]["against_account"] %}
|
||||
{% if (data[i]["reference"]) { %}
|
||||
<br>{%= __("Reference") %}: {%= data[i]["reference"] %}
|
||||
{% if (data[i]["reference_no"]) { %}
|
||||
<br>{%= __("Reference") %}: {%= data[i]["reference_no"] %}
|
||||
{% if (data[i]["ref_date"]) { %}
|
||||
<br>{%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i]["ref_date"]) %}
|
||||
{% } %}
|
||||
@ -38,7 +38,7 @@
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>{%= data[i]["journal_entry"] %}</td>
|
||||
<td>{%= data[i]["payment_entry"] %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i]["debit"]) %}</td>
|
||||
<td style="text-align: right">{%= format_currency(data[i]["credit"]) %}</td>
|
||||
</tr>
|
||||
|
@ -129,7 +129,7 @@ def get_entries(filters):
|
||||
reference_no, reference_date as ref_date,
|
||||
if(paid_to=%(account)s, received_amount, 0) as debit,
|
||||
if(paid_from=%(account)s, paid_amount, 0) as credit,
|
||||
posting_date, party as against_account, clearance_date,
|
||||
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
|
||||
if(paid_to=%(account)s, paid_to_account_currency, paid_from_account_currency) as account_currency
|
||||
from `tabPayment Entry`
|
||||
where
|
||||
|
1
erpnext/accounts/report/cash_flow/cash_flow.html
Normal file
1
erpnext/accounts/report/cash_flow/cash_flow.html
Normal file
@ -0,0 +1 @@
|
||||
{% include "accounts/report/financial_statements.html" %}
|
@ -0,0 +1 @@
|
||||
{% include "accounts/report/financial_statements.html" %}
|
@ -50,6 +50,19 @@ frappe.query_reports["Trial Balance for Party"] = {
|
||||
"options": ["Customer", "Supplier"],
|
||||
"default": "Customer"
|
||||
},
|
||||
{
|
||||
"fieldname":"party",
|
||||
"label": __("Party"),
|
||||
"fieldtype": "Dynamic Link",
|
||||
"get_options": function() {
|
||||
var party_type = frappe.query_report_filters_by_name.party_type.get_value();
|
||||
var party = frappe.query_report_filters_by_name.party.get_value();
|
||||
if(party && !party_type) {
|
||||
frappe.throw(__("Please select Party Type first"));
|
||||
}
|
||||
return party_type;
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldname": "show_zero_values",
|
||||
"label": __("Show zero values"),
|
||||
|
@ -20,13 +20,23 @@ def execute(filters=None):
|
||||
|
||||
def get_data(filters, show_party_name):
|
||||
party_name_field = "customer_name" if filters.get("party_type")=="Customer" else "supplier_name"
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field], order_by="name")
|
||||
party_filters = {"name": filters.get("party")} if filters.get("party") else {}
|
||||
parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
|
||||
filters = party_filters, order_by="name")
|
||||
company_currency = frappe.db.get_value("Company", filters.company, "default_currency")
|
||||
opening_balances = get_opening_balances(filters)
|
||||
balances_within_period = get_balances_within_period(filters)
|
||||
|
||||
data = []
|
||||
total_debit, total_credit = 0, 0
|
||||
# total_debit, total_credit = 0, 0
|
||||
total_row = frappe._dict({
|
||||
"opening_debit": 0,
|
||||
"opening_credit": 0,
|
||||
"debit": 0,
|
||||
"credit": 0,
|
||||
"closing_debit": 0,
|
||||
"closing_credit": 0
|
||||
})
|
||||
for party in parties:
|
||||
row = { "party": party.name }
|
||||
if show_party_name:
|
||||
@ -46,10 +56,6 @@ def get_data(filters, show_party_name):
|
||||
"credit": credit
|
||||
})
|
||||
|
||||
# totals
|
||||
total_debit += debit
|
||||
total_credit += credit
|
||||
|
||||
# closing
|
||||
closing_debit, closing_credit = toggle_debit_credit(opening_debit + debit, opening_credit + credit)
|
||||
row.update({
|
||||
@ -57,6 +63,10 @@ def get_data(filters, show_party_name):
|
||||
"closing_credit": closing_credit
|
||||
})
|
||||
|
||||
# totals
|
||||
for col in total_row:
|
||||
total_row[col] += row.get(col)
|
||||
|
||||
row.update({
|
||||
"currency": company_currency
|
||||
})
|
||||
@ -69,13 +79,12 @@ def get_data(filters, show_party_name):
|
||||
data.append(row)
|
||||
|
||||
# Add total row
|
||||
if total_debit or total_credit:
|
||||
data.append({
|
||||
"party": "'" + _("Totals") + "'",
|
||||
"debit": total_debit,
|
||||
"credit": total_credit,
|
||||
"currency": company_currency
|
||||
})
|
||||
|
||||
total_row.update({
|
||||
"party": "'" + _("Totals") + "'",
|
||||
"currency": company_currency
|
||||
})
|
||||
data.append(total_row)
|
||||
|
||||
return data
|
||||
|
||||
|
@ -371,6 +371,12 @@ def get_data():
|
||||
"doctype": "GL Entry",
|
||||
"is_query_report": True,
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"name": "Profitability Analysis",
|
||||
"doctype": "GL Entry",
|
||||
"is_query_report": True,
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"name": "Payment Period Based On Invoice Date",
|
||||
|
BIN
erpnext/docs/assets/img/buying/add_taxes_to_doc.png
Normal file
BIN
erpnext/docs/assets/img/buying/add_taxes_to_doc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 154 KiB |
BIN
erpnext/docs/assets/img/buying/buying_flow.png
Normal file
BIN
erpnext/docs/assets/img/buying/buying_flow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
erpnext/docs/assets/img/buying/show_tax_breakup.png
Normal file
BIN
erpnext/docs/assets/img/buying/show_tax_breakup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
@ -7,7 +7,7 @@ Supplier Quotation.
|
||||
|
||||
#### Purchase Order Flow Chart
|
||||
|
||||

|
||||

|
||||
|
||||
In ERPNext, you can also make a Purchase Order directly by going to:
|
||||
|
||||
@ -39,6 +39,12 @@ which you collect from your Customer. In many regions, what you pay to your
|
||||
government is only the difference between what you collect from your Customer
|
||||
and what you pay to your Supplier. This is called Value Added Tax (VAT).
|
||||
|
||||
#### Add Taxes in Purchase Order
|
||||
<img class="screenshot" alt="Purchase Order" src="{{docs_base_url}}/assets/img/buying/add_taxes_to_doc.png">
|
||||
|
||||
#### Show Tax break-up
|
||||
<img class="screenshot" alt="Purchase Order" src="{{docs_base_url}}/assets/img/buying/show_tax_breakup.png">
|
||||
|
||||
For example you buy Items worth X and sell them for 1.3X. So your Customer
|
||||
pays 1.3 times the tax you pay your Supplier. Since you have already paid tax
|
||||
to your Supplier for X, what you owe your government is only the tax on 0.3X.
|
||||
|
@ -8,7 +8,7 @@ You can make a supplier quotation from a Material Request
|
||||
|
||||
#### Supplier Quotation Flow-Chart
|
||||
|
||||

|
||||

|
||||
|
||||
You can also make a Supplier Quotation directly from:
|
||||
|
||||
@ -30,4 +30,15 @@ Supplier Quotations are not necessary for most small businesses. Always
|
||||
evaluate the cost of collecting information to the value it really provides!
|
||||
You could only do this for high value items.
|
||||
|
||||
#### Taxes
|
||||
If your Supplier is going to charge you additional taxes or charge like a shipping or insurance charge, you can add it here. It will help you to accurately track your costs. Also, if some of these charges add to the value of the product you will have to mention them in the Taxes table. You can also use templates for your taxes. For more information on setting up your taxes see the Purchase Taxes and Charges Template.
|
||||
|
||||
You can select relevant tax by going to "Taxes and Charges" section and adding an entry to the table as shown below,
|
||||
|
||||
<img class="screenshot" alt="Supplier Quotation" src="{{docs_base_url}}/assets/img/buying/add_taxes_to_doc.png">
|
||||
|
||||
Besides, in case of multiple items you can keep track of taxes on each by clicking "Show tax break-up"
|
||||
|
||||
<img class="screenshot" alt="Supplier Quotation" src="{{docs_base_url}}/assets/img/buying/show_tax_breakup.png">
|
||||
|
||||
{next}
|
||||
|
@ -486,7 +486,9 @@ class ProductionPlanningTool(Document):
|
||||
"qty": requested_qty,
|
||||
"schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)),
|
||||
"warehouse": self.purchase_request_for_warehouse,
|
||||
"sales_order": sales_order if sales_order!="No Sales Order" else None
|
||||
"sales_order": sales_order if sales_order!="No Sales Order" else None,
|
||||
"project": frappe.db.get_value("Sales Order", sales_order, "project") \
|
||||
if sales_order!="No Sales Order" else None
|
||||
})
|
||||
|
||||
material_request.flags.ignore_permissions = 1
|
||||
|
@ -1,17 +1,19 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
|
||||
|
||||
//--------- ONLOAD -------------
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
frappe.call({
|
||||
type:"GET",
|
||||
method:"erpnext.manufacturing.doctype.workstation.workstation.get_default_holiday_list",
|
||||
callback: function(r) {
|
||||
if(!r.exe && r.message){
|
||||
cur_frm.set_value("holiday_list", r.message);
|
||||
}
|
||||
frappe.ui.form.on("Workstation", {
|
||||
onload: function(frm) {
|
||||
if(frm.is_new())
|
||||
{
|
||||
frappe.call({
|
||||
type:"GET",
|
||||
method:"erpnext.manufacturing.doctype.workstation.workstation.get_default_holiday_list",
|
||||
callback: function(r) {
|
||||
if(!r.exe && r.message){
|
||||
cur_frm.set_value("holiday_list", r.message);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
@ -351,3 +351,4 @@ erpnext.patches.v7_1.update_invoice_status
|
||||
erpnext.patches.v7_0.po_status_issue_for_pr_return
|
||||
erpnext.patches.v7_1.update_missing_salary_component_type
|
||||
erpnext.patches.v7_1.rename_quality_inspection_field
|
||||
erpnext.patches.v7_0.update_autoname_field
|
||||
|
@ -6,6 +6,8 @@ from erpnext.patches.v7_0.migrate_schools_to_erpnext import reload_doctypes_for_
|
||||
|
||||
def execute():
|
||||
'''hide new style icons if old ones are set'''
|
||||
frappe.reload_doc('desk', 'doctype', 'desktop_icon')
|
||||
|
||||
reload_doctypes_for_schools_icons()
|
||||
|
||||
sync_desktop_icons()
|
||||
|
14
erpnext/patches/v7_0/update_autoname_field.py
Normal file
14
erpnext/patches/v7_0/update_autoname_field.py
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
doctypes = frappe.db.sql(""" select name, autoname from `tabDocType`
|
||||
where autoname like 'field:%' and allow_rename = 1""", as_dict=1)
|
||||
|
||||
for doctype in doctypes:
|
||||
fieldname = doctype.autoname.split(":")[1]
|
||||
if fieldname:
|
||||
frappe.db.sql(""" update `tab%s` set %s = name """%(doctype.name, fieldname))
|
@ -66,27 +66,41 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
});
|
||||
}
|
||||
|
||||
if(this.frm.fields_dict["packed_items"].grid.get_field('batch_no')) {
|
||||
this.frm.set_query("batch_no", "packed_items", function(doc, cdt, cdn) {
|
||||
return me.set_query_for_batch(doc, cdt, cdn)
|
||||
});
|
||||
}
|
||||
|
||||
if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
|
||||
this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
if(!item.item_code) {
|
||||
frappe.throw(__("Please enter Item Code to get batch no"));
|
||||
} else {
|
||||
filters = {
|
||||
'item_code': item.item_code,
|
||||
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
|
||||
}
|
||||
if(item.warehouse) filters["warehouse"] = item.warehouse
|
||||
|
||||
return {
|
||||
query : "erpnext.controllers.queries.get_batch_no",
|
||||
filters: filters
|
||||
}
|
||||
}
|
||||
return me.set_query_for_batch(doc, cdt, cdn)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
set_query_for_batch: function(doc, cdt, cdn) {
|
||||
// Show item's batches in the dropdown of batch no
|
||||
|
||||
var me = this;
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
|
||||
if(!item.item_code) {
|
||||
frappe.throw(__("Please enter Item Code to get batch no"));
|
||||
} else {
|
||||
filters = {
|
||||
'item_code': item.item_code,
|
||||
'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
|
||||
}
|
||||
if(item.warehouse) filters["warehouse"] = item.warehouse
|
||||
|
||||
return {
|
||||
query : "erpnext.controllers.queries.get_batch_no",
|
||||
filters: filters
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this._super();
|
||||
this.frm.toggle_display("customer_name",
|
||||
|
@ -372,6 +372,7 @@ def raise_production_orders(material_request):
|
||||
mr= frappe.get_doc("Material Request", material_request)
|
||||
errors =[]
|
||||
production_orders = []
|
||||
default_wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
|
||||
for d in mr.items:
|
||||
if (d.qty - d.ordered_qty) >0:
|
||||
if frappe.db.get_value("BOM", {"item": d.item_code, "is_default": 1}):
|
||||
@ -379,6 +380,7 @@ def raise_production_orders(material_request):
|
||||
prod_order.production_item = d.item_code
|
||||
prod_order.qty = d.qty - d.ordered_qty
|
||||
prod_order.fg_warehouse = d.warehouse
|
||||
prod_order.wip_warehouse = default_wip_warehouse
|
||||
prod_order.description = d.description
|
||||
prod_order.stock_uom = d.uom
|
||||
prod_order.expected_delivery_date = d.schedule_date
|
||||
|
@ -16,7 +16,7 @@ class PackedItem(Document):
|
||||
def get_product_bundle_items(item_code):
|
||||
return frappe.db.sql("""select t1.item_code, t1.qty, t1.uom, t1.description
|
||||
from `tabProduct Bundle Item` t1, `tabProduct Bundle` t2
|
||||
where t2.new_item_code=%s and t1.parent = t2.name""", item_code, as_dict=1)
|
||||
where t2.new_item_code=%s and t1.parent = t2.name order by t1.idx""", item_code, as_dict=1)
|
||||
|
||||
def get_packing_item_details(item):
|
||||
return frappe.db.sql("""select item_name, description, stock_uom from `tabItem`
|
||||
|
Loading…
x
Reference in New Issue
Block a user