Merge branch 'develop'

This commit is contained in:
Pratik Vyas 2014-09-16 15:58:28 +05:30
commit 54938d431c
142 changed files with 6460 additions and 4781 deletions

View File

@ -1,5 +1,9 @@
# Contributing to Frappe / ERPNext
### Update 16-Sep-14
Please send pull requests to branch v5.0
## Reporting issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.

View File

@ -1 +1 @@
__version__ = '4.3.0'
__version__ = '4.4.0'

View File

@ -169,15 +169,13 @@ class Account(Document):
def validate_due_date(self, posting_date, due_date):
credit_days = (self.credit_days or frappe.db.get_value("Company", self.company, "credit_days"))
if credit_days is None:
return
posting_date, due_date = getdate(posting_date), getdate(due_date)
diff = (due_date - posting_date).days
if diff < 0:
frappe.throw(_("Due Date cannot be before Posting Date"))
elif diff > credit_days:
elif credit_days is not None and diff > credit_days:
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
"credit_controller") in frappe.user.get_roles()

View File

@ -17,15 +17,19 @@ class CForm(Document):
inv = frappe.db.sql("""select c_form_applicable, c_form_no from
`tabSales Invoice` where name = %s and docstatus = 1""", d.invoice_no)
if inv[0][0] != 'Yes':
if inv and inv[0][0] != 'Yes':
frappe.throw("C-form is not applicable for Invoice: %s" % d.invoice_no)
elif inv[0][1] and inv[0][1] != self.name:
elif inv and inv[0][1] and inv[0][1] != self.name:
frappe.throw("""Invoice %s is tagged in another C-form: %s.
If you want to change C-form no for this invoice,
please remove invoice no from the previous c-form and then try again""" %
(d.invoice_no, inv[0][1]))
elif not inv:
frappe.throw("Row %s: Invoice %s is invalid, it might be cancelled / does not exist. \
Please enter a valid Invoice" % d.idx, d.invoice_no)
def on_update(self):
""" Update C-Form No on invoices"""
self.set_total_invoiced_amount()

View File

@ -25,7 +25,8 @@ class GLEntry(Document):
validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher
if self.against_voucher and update_outstanding == 'Yes':
if self.against_voucher_type in ['Journal Voucher', 'Sales Invoice', 'Purchase Invoice'] \
and self.against_voucher and update_outstanding == 'Yes':
update_outstanding_amt(self.account, self.against_voucher_type,
self.against_voucher)

View File

@ -339,6 +339,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
@ -446,7 +447,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-14 01:37:14.822939",
"modified": "2014-09-09 05:35:31.217863",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Voucher",

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt, fmt_money, formatdate, getdate
from frappe import msgprint, _
from frappe import msgprint, _, scrub
from erpnext.setup.utils import get_company_currency
from erpnext.controllers.accounts_controller import AccountsController
@ -35,18 +35,35 @@ class JournalVoucher(AccountsController):
self.create_remarks()
self.set_aging_date()
self.set_print_format_fields()
self.validate_against_sales_order()
self.validate_against_purchase_order()
def on_submit(self):
if self.voucher_type in ['Bank Voucher', 'Contra Voucher', 'Journal Entry']:
self.check_credit_days()
self.make_gl_entries()
self.check_credit_limit()
self.update_advance_paid()
def update_advance_paid(self):
advance_paid = frappe._dict()
for d in self.get("entries"):
if d.is_advance:
if d.against_sales_order:
advance_paid.setdefault("Sales Order", []).append(d.against_sales_order)
elif d.against_purchase_order:
advance_paid.setdefault("Purchase Order", []).append(d.against_purchase_order)
for voucher_type, order_list in advance_paid.items():
for voucher_no in list(set(order_list)):
frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
def on_cancel(self):
from erpnext.accounts.utils import remove_against_link_from_jv
remove_against_link_from_jv(self.doctype, self.name, "against_jv")
self.make_gl_entries(1)
self.update_advance_paid()
def validate_cheque_info(self):
if self.voucher_type in ['Bank Voucher']:
@ -64,7 +81,8 @@ class JournalVoucher(AccountsController):
master_type = frappe.db.get_value("Account", d.account, "master_type")
if (master_type == 'Customer' and flt(d.credit) > 0) or \
(master_type == 'Supplier' and flt(d.debit) > 0):
msgprint(_("Please check 'Is Advance' against Account {0} if this is an advance entry.").format(d.account))
msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this \
is an advance entry.").format(d.idx, d.account))
def validate_against_jv(self):
for d in self.get('entries'):
@ -90,24 +108,86 @@ class JournalVoucher(AccountsController):
.format(d.against_jv, dr_or_cr))
def validate_against_sales_invoice(self):
for d in self.get("entries"):
if d.against_invoice:
if d.debit > 0:
frappe.throw(_("Row {0}: Debit entry can not be linked with a Sales Invoice")
.format(d.idx))
if frappe.db.get_value("Sales Invoice", d.against_invoice, "debit_to") != d.account:
frappe.throw(_("Row {0}: Account does not match with \
Sales Invoice Debit To account").format(d.idx, d.account))
payment_against_voucher = self.validate_account_in_against_voucher("against_invoice", "Sales Invoice")
self.validate_against_invoice_fields("Sales Invoice", payment_against_voucher)
def validate_against_purchase_invoice(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_voucher", "Purchase Invoice")
self.validate_against_invoice_fields("Purchase Invoice", payment_against_voucher)
def validate_against_sales_order(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_sales_order", "Sales Order")
self.validate_against_order_fields("Sales Order", payment_against_voucher)
def validate_against_purchase_order(self):
payment_against_voucher = self.validate_account_in_against_voucher("against_purchase_order", "Purchase Order")
self.validate_against_order_fields("Purchase Order", payment_against_voucher)
def validate_account_in_against_voucher(self, against_field, doctype):
payment_against_voucher = frappe._dict()
field_dict = {'Sales Invoice': "Debit To",
'Purchase Invoice': "Credit To",
'Sales Order': "Customer",
'Purchase Order': "Supplier"
}
for d in self.get("entries"):
if d.against_voucher:
if flt(d.credit) > 0:
frappe.throw(_("Row {0}: Credit entry can not be linked with a Purchase Invoice")
.format(d.idx))
if frappe.db.get_value("Purchase Invoice", d.against_voucher, "credit_to") != d.account:
frappe.throw(_("Row {0}: Account does not match with \
Purchase Invoice Credit To account").format(d.idx, d.account))
if d.get(against_field):
dr_or_cr = "credit" if against_field in ["against_invoice", "against_sales_order"] \
else "debit"
if against_field in ["against_invoice", "against_sales_order"] \
and flt(d.debit) > 0:
frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, doctype))
if against_field in ["against_voucher", "against_purchase_order"] \
and flt(d.credit) > 0:
frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, doctype))
voucher_account = frappe.db.get_value(doctype, d.get(against_field), \
scrub(field_dict.get(doctype)))
account_master_name = frappe.db.get_value("Account", d.account, "master_name")
if against_field in ["against_invoice", "against_voucher"] \
and voucher_account != d.account:
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} account") \
.format(d.idx, d.account, doctype, field_dict.get(doctype)))
if against_field in ["against_sales_order", "against_purchase_order"]:
if voucher_account != account_master_name:
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} Name") \
.format(d.idx, d.account, doctype, field_dict.get(doctype)))
elif d.is_advance == "Yes":
payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
return payment_against_voucher
def validate_against_invoice_fields(self, doctype, payment_against_voucher):
for voucher_no, payment_list in payment_against_voucher.items():
voucher_properties = frappe.db.get_value(doctype, voucher_no,
["docstatus", "outstanding_amount"])
if voucher_properties[0] != 1:
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
if flt(voucher_properties[1]) < flt(sum(payment_list)):
frappe.throw(_("Payment against {0} {1} cannot be greater \
than Outstanding Amount {2}").format(doctype, voucher_no, voucher_properties[1]))
def validate_against_order_fields(self, doctype, payment_against_voucher):
for voucher_no, payment_list in payment_against_voucher.items():
voucher_properties = frappe.db.get_value(doctype, voucher_no,
["docstatus", "per_billed", "advance_paid", "grand_total"])
if voucher_properties[0] != 1:
frappe.throw(_("{0} {1} is not submitted").format(doctype, voucher_no))
if flt(voucher_properties[1]) >= 100:
frappe.throw(_("{0} {1} is fully billed").format(doctype, voucher_no))
if flt(voucher_properties[3]) < flt(voucher_properties[2]) + flt(sum(payment_list)):
frappe.throw(_("Advance paid against {0} {1} cannot be greater \
than Grand Total {2}").format(doctype, voucher_no, voucher_properties[3]))
def set_against_account(self):
accounts_debited, accounts_credited = [], []
@ -147,7 +227,13 @@ class JournalVoucher(AccountsController):
for d in self.get('entries'):
if d.against_invoice and d.credit:
currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
r.append(_("{0} {1} against Invoice {2}").format(currency, fmt_money(flt(d.credit)), d.against_invoice))
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_invoice))
if d.against_sales_order and d.credit:
currency = frappe.db.get_value("Sales Order", d.against_sales_order, "currency")
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_sales_order))
if d.against_voucher and d.debit:
bill_no = frappe.db.sql("""select bill_no, bill_date, currency
@ -158,13 +244,17 @@ class JournalVoucher(AccountsController):
fmt_money(flt(d.debit)), bill_no[0][0],
bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
if d.against_purchase_order and d.debit:
currency = frappe.db.get_value("Purchase Order", d.against_purchase_order, "currency")
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
d.against_purchase_order))
if self.user_remark:
r.append(_("Note: {0}").format(self.user_remark))
if r:
self.remark = ("\n").join(r)
else:
frappe.msgprint(_("User Remarks is mandatory"), raise_exception=frappe.MandatoryError)
self.remark = ("\n").join(r) #User Remarks is not mandatory
def set_aging_date(self):
if self.is_opening != 'Yes':
@ -264,14 +354,18 @@ class JournalVoucher(AccountsController):
"against": d.against_account,
"debit": flt(d.debit, self.precision("debit", "entries")),
"credit": flt(d.credit, self.precision("credit", "entries")),
"against_voucher_type": ((d.against_voucher and "Purchase Invoice")
or (d.against_invoice and "Sales Invoice")
or (d.against_jv and "Journal Voucher")),
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv,
"against_voucher_type": (("Purchase Invoice" if d.against_voucher else None)
or ("Sales Invoice" if d.against_invoice else None)
or ("Journal Voucher" if d.against_jv else None)
or ("Sales Order" if d.against_sales_order else None)
or ("Purchase Order" if d.against_purchase_order else None)),
"against_voucher": d.against_voucher or d.against_invoice or d.against_jv
or d.against_sales_order or d.against_purchase_order,
"remarks": self.remark,
"cost_center": d.cost_center
})
)
if gl_map:
make_gl_entries(gl_map, cancel=cancel, adv_adj=adv_adj)

View File

@ -1,41 +1,88 @@
# 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 unittest
import frappe
import unittest, frappe
from frappe.utils import flt
class TestJournalVoucher(unittest.TestCase):
def test_journal_voucher_with_against_jv(self):
self.clear_account_balance()
jv_invoice = frappe.copy_doc(test_records[2])
jv_invoice.insert()
jv_invoice.submit()
base_jv = frappe.copy_doc(test_records[0])
self.jv_against_voucher_testcase(base_jv, jv_invoice)
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s""",
("_Test Customer - _TC", jv_invoice.name)))
def test_jv_against_sales_order(self):
from erpnext.selling.doctype.sales_order.test_sales_order \
import test_records as so_test_records
sales_order = frappe.copy_doc(so_test_records[0])
base_jv = frappe.copy_doc(test_records[0])
self.jv_against_voucher_testcase(base_jv, sales_order)
def test_jv_against_purchase_order(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order \
import test_records as po_test_records
purchase_order = frappe.copy_doc(po_test_records[0])
base_jv = frappe.copy_doc(test_records[1])
self.jv_against_voucher_testcase(base_jv, purchase_order)
def jv_against_voucher_testcase(self, base_jv, test_voucher):
dr_or_cr = "credit" if test_voucher.doctype in ["Sales Order", "Journal Voucher"] else "debit"
field_dict = {'Journal Voucher': "against_jv",
'Sales Order': "against_sales_order",
'Purchase Order': "against_purchase_order"
}
self.clear_account_balance()
test_voucher.insert()
test_voucher.submit()
if test_voucher.doctype == "Journal Voucher":
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where account = %s and docstatus = 1 and parent = %s""",
("_Test Customer - _TC", test_voucher.name)))
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (test_voucher.name)))
jv_payment = frappe.copy_doc(test_records[0])
jv_payment.get("entries")[0].against_jv = jv_invoice.name
jv_payment.insert()
jv_payment.submit()
base_jv.get("entries")[0].is_advance = "Yes" if (test_voucher.doctype in ["Sales Order", "Purchase Order"]) else "No"
base_jv.get("entries")[0].set(field_dict.get(test_voucher.doctype), test_voucher.name)
base_jv.insert()
base_jv.submit()
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
where %s=%s""" % (field_dict.get(test_voucher.doctype), '%s'), (submitted_voucher.name)))
self.assertTrue(frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s and credit=400""", jv_invoice.name))
where %s=%s and %s=400""" % (field_dict.get(submitted_voucher.doctype), '%s', dr_or_cr), (submitted_voucher.name)))
# cancel jv_invoice
jv_invoice.cancel()
if base_jv.get("entries")[0].is_advance == "Yes":
self.advance_paid_testcase(base_jv, submitted_voucher, dr_or_cr)
self.cancel_against_voucher_testcase(submitted_voucher)
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", jv_invoice.name))
def advance_paid_testcase(self, base_jv, test_voucher, dr_or_cr):
#Test advance paid field
advance_paid = frappe.db.sql("""select advance_paid from `tab%s`
where name=%s""" % (test_voucher.doctype, '%s'), (test_voucher.name))
payment_against_order = base_jv.get("entries")[0].get(dr_or_cr)
self.assertTrue(flt(advance_paid[0][0]) == flt(payment_against_order))
def cancel_against_voucher_testcase(self, test_voucher):
if test_voucher.doctype == "Journal Voucher":
# if test_voucher is a Journal Voucher, test cancellation of test_voucher
test_voucher.cancel()
self.assertTrue(not frappe.db.sql("""select name from `tabJournal Voucher Detail`
where against_jv=%s""", test_voucher.name))
elif test_voucher.doctype in ["Sales Order", "Purchase Order"]:
# if test_voucher is a Sales Order/Purchase Order, test error on cancellation of test_voucher
submitted_voucher = frappe.get_doc(test_voucher.doctype, test_voucher.name)
self.assertRaises(frappe.LinkExistsError, submitted_voucher.cancel)
def test_jv_against_stock_account(self):
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory

View File

@ -117,11 +117,6 @@
"print_hide": 0,
"search_index": 1
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "against_jv",
"fieldtype": "Link",
@ -135,6 +130,25 @@
"print_hide": 0,
"search_index": 1
},
{
"fieldname": "col_break3",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "against_sales_order",
"fieldtype": "Link",
"label": "Against Sales Order",
"options": "Sales Order",
"permlevel": 0
},
{
"fieldname": "against_purchase_order",
"fieldtype": "Link",
"label": "Against Purchase Order",
"options": "Purchase Order",
"permlevel": 0
},
{
"fieldname": "is_advance",
"fieldtype": "Select",
@ -160,7 +174,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-07-25 03:16:51.149899",
"modified": "2014-08-20 12:19:55.049973",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Voucher Detail",

View File

@ -36,8 +36,8 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
}
});
var help_content = '<i class="icon-hand-right"></i> Note:<br>'+
'<ul>If you are unable to match the exact amount, then amend your Journal Voucher and split rows such that payment amount match the invoice amount.</ul>';
var help_content = '<i class="icon-hand-right"></i> ' + __("Note") + ':<br>'+
'<ul>' + __("If you are unable to match the exact amount, then amend your Journal Voucher and split rows such that payment amount match the invoice amount.") + '</ul>';
this.frm.set_value("reconcile_help", help_content);
},

View File

@ -0,0 +1,217 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// For license information, please see license.txt
frappe.provide("erpnext.payment_tool");
// Help content
frappe.ui.form.on("Payment Tool", "onload", function(frm) {
frm.set_value("make_jv_help", '<i class="icon-hand-right"></i> '
+ __("Note: If payment is not made against any reference, make Journal Voucher manually."));
frm.set_query("payment_account", function() {
return {
filters: [
['Account', 'account_type', 'in', 'Bank, Cash'],
['Account', 'group_or_ledger', '=', 'Ledger'],
['Account', 'company', '=', frm.doc.company]
]
}
});
frm.set_query("against_voucher_type", "payment_tool_details", function() {
return {
filters: {"name": ["in", ["Sales Invoice", "Purchase Invoice", "Journal Voucher", "Sales Order", "Purchase Order"]]}
};
});
});
frappe.ui.form.on("Payment Tool", "refresh", function(frm) {
frappe.ui.form.trigger("Payment Tool", "party_type");
});
frappe.ui.form.on("Payment Tool", "party_type", function(frm) {
frm.toggle_reqd("customer", frm.doc.party_type == "Customer");
frm.toggle_reqd("supplier", frm.doc.party_type == "Supplier");
});
frappe.ui.form.on("Payment Tool", "company", function(frm) {
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
frappe.ui.form.on("Payment Tool", "received_or_paid", function(frm) {
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
// Fetch bank/cash account based on payment mode
cur_frm.add_fetch("payment_mode", "default_account", "payment_account");
// Set party account name
frappe.ui.form.on("Payment Tool", "customer", function(frm) {
erpnext.payment_tool.set_party_account(frm);
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
frappe.ui.form.on("Payment Tool", "supplier", function(frm) {
erpnext.payment_tool.set_party_account(frm);
erpnext.payment_tool.check_mandatory_to_set_button(frm);
});
erpnext.payment_tool.check_mandatory_to_set_button = function(frm) {
if (frm.doc.company && frm.doc.party_type && frm.doc.received_or_paid && (frm.doc.customer || frm.doc.supplier)) {
frm.fields_dict.get_outstanding_vouchers.$input.addClass("btn-primary");
}
}
//Set Button color
erpnext.payment_tool.set_party_account = function(frm) {
if(frm.doc.party_type == "Customer") {
var party_name = frm.doc.customer;
} else {
var party_name = frm.doc.supplier;
}
return frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_party_account',
args: {
party_type: frm.doc.party_type,
party_name: party_name
},
callback: function(r, rt) {
if(!r.exc) {
frm.set_value("party_account", r.message);
}
}
});
}
// Get outstanding vouchers
frappe.ui.form.on("Payment Tool", "get_outstanding_vouchers", function(frm) {
erpnext.payment_tool.check_mandatory_to_fetch(frm.doc);
frm.set_value("payment_tool_details", []);
return frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_outstanding_vouchers',
args: {
args: {
"company": frm.doc.company,
"party_type": frm.doc.party_type,
"received_or_paid": frm.doc.received_or_paid,
"party_name": frm.doc.party_type == "Customer" ? frm.doc.customer : frm.doc.supplier,
"party_account": frm.doc.party_account
}
},
callback: function(r, rt) {
if(r.message) {
frm.fields_dict.get_outstanding_vouchers.$input.removeClass("btn-primary");
frm.fields_dict.make_journal_voucher.$input.addClass("btn-primary");
frappe.model.clear_table(frm.doc, "payment_tool_details");
$.each(r.message, function(i, d) {
var invoice_detail = frappe.model.add_child(frm.doc, "Payment Tool Detail", "payment_tool_details");
invoice_detail.against_voucher_type = d.voucher_type;
invoice_detail.against_voucher_no = d.voucher_no;
invoice_detail.total_amount = d.invoice_amount;
invoice_detail.outstanding_amount = d.outstanding_amount;
});
}
refresh_field("payment_tool_details");
erpnext.payment_tool.set_total_payment_amount(frm);
}
});
});
// validate against_voucher_type
frappe.ui.form.on("Payment Tool Detail", "against_voucher_type", function(frm) {
erpnext.payment_tool.validate_against_voucher(frm);
});
erpnext.payment_tool.validate_against_voucher = function(frm) {
$.each(frm.doc.payment_tool_details || [], function(i, row) {
if(frm.doc.party_type=="Customer"
&& !in_list(["Sales Order", "Sales Invoice", "Journal Voucher"], row.against_voucher_type)) {
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
frappe.throw(__("Against Voucher Type must be one of Sales Order, Sales Invoice or Journal Voucher"))
}
if(frm.doc.party_type=="Supplier"
&& !in_list(["Purchase Order", "Purchase Invoice", "Journal Voucher"], row.against_voucher_type)) {
frappe.model.set_value(row.doctype, row.name, "against_voucher_type", "");
frappe.throw(__("Against Voucher Type must be one of Purchase Order, Purchase Invoice or Journal Voucher"))
}
});
}
// validate against_voucher_type
frappe.ui.form.on("Payment Tool Detail", "against_voucher_no", function(frm, cdt, cdn) {
var row = locals[cdt][cdn];
frappe.call({
method: 'erpnext.accounts.doctype.payment_tool.payment_tool.get_against_voucher_amount',
args: {
"against_voucher_type": row.against_voucher_type,
"against_voucher_no": row.against_voucher_no
},
callback: function(r) {
if(!r.exc) {
$.each(r.message, function(k, v) {
frappe.model.set_value(cdt, cdn, k, v);
});
}
}
});
});
// Set total payment amount
frappe.ui.form.on("Payment Tool Detail", "payment_amount", function(frm) {
erpnext.payment_tool.set_total_payment_amount(frm);
});
frappe.ui.form.on("Payment Tool Detail", "payment_tool_details_remove", function(frm) {
erpnext.payment_tool.set_total_payment_amount(frm);
});
erpnext.payment_tool.set_total_payment_amount = function(frm) {
var total_amount = 0.00;
$.each(frm.doc.payment_tool_details || [], function(i, row) {
if (row.payment_amount && (row.payment_amount <= row.outstanding_amount)) {
total_amount = total_amount + row.payment_amount;
} else {
if(row.payment_amount < 0)
msgprint(__("Row {0}: Payment amount can not be negative", [row.idx]));
else if(row.payment_amount >= row.outstanding_amount)
msgprint(__("Row {0}: Payment Amount cannot be greater than Outstanding Amount", [__(row.idx)]));
frappe.model.set_value(row.doctype, row.name, "payment_amount", 0.0);
}
});
frm.set_value("total_payment_amount", total_amount);
}
// Make Journal voucher
frappe.ui.form.on("Payment Tool", "make_journal_voucher", function(frm) {
erpnext.payment_tool.check_mandatory_to_fetch(frm.doc);
return frappe.call({
method: 'make_journal_voucher',
doc: frm.doc,
callback: function(r) {
frm.fields_dict.make_journal_voucher.$input.addClass("btn-primary");
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
});
});
erpnext.payment_tool.check_mandatory_to_fetch = function(doc) {
var check_fields = [
['Company', doc.company],
['Party Type', doc.party_type],
['Received Or Paid', doc.received_or_paid],
['Customer / Supplier', doc.party_type == "Customer" ? doc.customer : doc.supplier]
];
$.each(check_fields, function(i, v) {
if(!v[1]) frappe.throw(__("Please select {0} first", [v[0]]));
});
}

View File

@ -0,0 +1,381 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2014-07-23 15:12:27.746665",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"fieldname": "sec_break1",
"fieldtype": "Section Break",
"label": "Party Details",
"permlevel": 0
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company",
"permlevel": 0,
"reqd": 1
},
{
"allow_on_submit": 0,
"default": "Customer",
"fieldname": "party_type",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Party Type",
"no_copy": 0,
"options": "Customer\nSupplier",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.party_type == 'Customer')",
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Customer",
"no_copy": 0,
"options": "Customer",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.party_type == 'Supplier')",
"fieldname": "supplier",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Supplier",
"no_copy": 0,
"options": "Supplier",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "party_account",
"fieldtype": "Link",
"hidden": 1,
"label": "Party Account",
"no_copy": 1,
"options": "Account",
"permlevel": 0,
"read_only": 1
},
{
"allow_on_submit": 0,
"fieldname": "received_or_paid",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Received Or Paid",
"no_copy": 0,
"options": "Received\nPaid",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "get_outstanding_vouchers",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Get Outstanding Vouchers",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Column Break 1",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_mode",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Mode",
"no_copy": 0,
"options": "Mode of Payment",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_account",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Account",
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "reference_no",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference No",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "reference_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Reference Date",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "sec_break3",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Against Voucher",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_tool_details",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Payment Tool Details",
"no_copy": 0,
"options": "Payment Tool Detail",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "section_break_19",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "total_payment_amount",
"fieldtype": "Currency",
"label": "Total Payment Amount",
"permlevel": 0,
"read_only": 1
},
{
"allow_on_submit": 0,
"fieldname": "make_journal_voucher",
"fieldtype": "Button",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Make Journal Voucher",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "data_22",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"depends_on": "eval:(doc.company && doc.party_type && doc.received_or_paid && (doc.customer || doc.supplier))",
"fieldname": "section_break_21",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "make_jv_help",
"fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 1,
"icon": "icon-magic",
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"modified": "2014-09-12 04:43:05.963218",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts Manager",
"set_user_permissions": 0,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 0,
"export": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Accounts User",
"set_user_permissions": 0,
"submit": 0,
"write": 1
}
],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,118 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _, scrub
from frappe.utils import flt
from frappe.model.document import Document
import json
class PaymentTool(Document):
def make_journal_voucher(self):
from erpnext.accounts.utils import get_balance_on
total_payment_amount = 0.00
invoice_voucher_type = {
'Sales Invoice': 'against_invoice',
'Purchase Invoice': 'against_voucher',
'Journal Voucher': 'against_jv',
'Sales Order': 'against_sales_order',
'Purchase Order': 'against_purchase_order',
}
jv = frappe.new_doc('Journal Voucher')
jv.voucher_type = 'Journal Entry'
jv.company = self.company
jv.cheque_no = self.reference_no
jv.cheque_date = self.reference_date
if not self.total_payment_amount:
frappe.throw(_("Please enter Payment Amount in atleast one row"))
for v in self.get("payment_tool_details"):
if not frappe.db.get_value(v.against_voucher_type, {"name": v.against_voucher_no}):
frappe.throw(_("Row {0}: {1} is not a valid {2}").format(v.idx, v.against_voucher_no,
v.against_voucher_type))
if v.payment_amount:
d1 = jv.append("entries")
d1.account = self.party_account
d1.balance = get_balance_on(self.party_account)
d1.set("debit" if self.received_or_paid=="Paid" else "credit", flt(v.payment_amount))
d1.set(invoice_voucher_type.get(v.against_voucher_type), v.against_voucher_no)
d1.set('is_advance', 'Yes' if v.against_voucher_type in ['Sales Order', 'Purchase Order'] else 'No')
total_payment_amount = flt(total_payment_amount) + flt(d1.debit) - flt(d1.credit)
d2 = jv.append("entries")
d2.account = self.payment_account
d2.set('debit' if total_payment_amount < 0 else 'credit', abs(total_payment_amount))
if self.payment_account:
d2.balance = get_balance_on(self.payment_account)
return jv.as_dict()
@frappe.whitelist()
def get_party_account(party_type, party_name):
return frappe.db.get_value("Account", {"master_type": party_type, "master_name": party_name})
@frappe.whitelist()
def get_outstanding_vouchers(args):
from erpnext.accounts.utils import get_outstanding_invoices
if not frappe.has_permission("Payment Tool"):
frappe.throw(_("No permission to use Payment Tool"), frappe.PermissionError)
args = json.loads(args)
if args.get("party_type") == "Customer" and args.get("received_or_paid") == "Received":
amount_query = "ifnull(debit, 0) - ifnull(credit, 0)"
elif args.get("party_type") == "Supplier" and args.get("received_or_paid") == "Paid":
amount_query = "ifnull(credit, 0) - ifnull(debit, 0)"
else:
frappe.throw(_("Please enter the Against Vouchers manually"))
# Get all outstanding sales /purchase invoices
outstanding_invoices = get_outstanding_invoices(amount_query, args.get("party_account"))
# Get all SO / PO which are not fully billed or aginst which full advance not paid
orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party_name"))
return outstanding_invoices + orders_to_be_billed
def get_orders_to_be_billed(party_type, party_name):
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
orders = frappe.db.sql("""
select
name as voucher_no,
ifnull(grand_total, 0) as invoice_amount,
(ifnull(grand_total, 0) - ifnull(advance_paid, 0)) as outstanding_amount,
transaction_date as posting_date
from
`tab%s`
where
%s = %s
and docstatus = 1
and ifnull(grand_total, 0) > ifnull(advance_paid, 0)
and ifnull(per_billed, 0) < 100.0
""" % (voucher_type, 'customer' if party_type == "Customer" else 'supplier', '%s'),
party_name, as_dict = True)
order_list = []
for d in orders:
d["voucher_type"] = voucher_type
order_list.append(d)
return order_list
@frappe.whitelist()
def get_against_voucher_amount(against_voucher_type, against_voucher_no):
if against_voucher_type in ["Sales Order", "Purchase Order"]:
select_cond = "grand_total as total_amount, ifnull(grand_total, 0) - ifnull(advance_paid, 0) as outstanding_amount"
elif against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
select_cond = "grand_total as total_amount, outstanding_amount"
elif against_voucher_type == "Journal Voucher":
select_cond = "total_debit as total_amount"
details = frappe.db.sql("""select {0} from `tab{1}` where name = %s"""
.format(select_cond, against_voucher_type), against_voucher_no, as_dict=1)
return details[0] if details else {}

View File

@ -0,0 +1,193 @@
# 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 unittest, frappe, json
from frappe.utils import flt
test_dependencies = ["Item"]
class TestPaymentTool(unittest.TestCase):
def test_make_journal_voucher(self):
from erpnext.accounts.doctype.journal_voucher.test_journal_voucher \
import test_records as jv_test_records
from erpnext.selling.doctype.sales_order.test_sales_order \
import test_records as so_test_records
from erpnext.buying.doctype.purchase_order.test_purchase_order \
import test_records as po_test_records
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice \
import test_records as si_test_records
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice \
import test_records as pi_test_records
self.clear_table_entries()
base_customer_jv = self.create_against_jv(jv_test_records[2], { "account": "_Test Customer 3 - _TC"})
base_supplier_jv = self.create_against_jv(jv_test_records[1], { "account": "_Test Supplier 1 - _TC"})
#Create SO with partial outstanding
so1 = self.create_voucher(so_test_records[0], {
"customer": "_Test Customer 3"
})
jv_against_so1 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_sales_order": so1.name
})
#Create SO with no outstanding
so2 = self.create_voucher(so_test_records[0], {
"customer": "_Test Customer 3"
})
jv_against_so2 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_sales_order": so2.name,
"credit": 1000
})
po = self.create_voucher(po_test_records[1], {
"supplier": "_Test Supplier 1"
})
#Create SI with partial outstanding
si1 = self.create_voucher(si_test_records[0], {
"customer": "_Test Customer 3",
"debit_to": "_Test Customer 3 - _TC"
})
jv_against_si1 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_invoice": si1.name
})
#Create SI with no outstanding
si2 = self.create_voucher(si_test_records[0], {
"customer": "_Test Customer 3",
"debit_to": "_Test Customer 3 - _TC"
})
jv_against_si2 = self.create_against_jv(jv_test_records[0], {
"account": "_Test Customer 3 - _TC",
"against_invoice": si2.name,
"credit": 561.80
})
pi = self.create_voucher(pi_test_records[0], {
"supplier": "_Test Supplier 1",
"credit_to": "_Test Supplier 1 - _TC"
})
#Create a dict containing properties and expected values
expected_outstanding = {
"Journal Voucher" : [base_customer_jv.name, 400.00],
"Sales Invoice" : [si1.name, 161.80],
"Purchase Invoice" : [pi.name, 1512.30],
"Sales Order" : [so1.name, 600.00],
"Purchase Order" : [po.name, 5000.00]
}
args = {
"company": "_Test Company",
"party_type": "Customer",
"received_or_paid": "Received",
"customer": "_Test Customer",
"party_account": "_Test Customer 3 - _TC",
"payment_mode": "Cheque",
"payment_account": "_Test Account Bank Account - _TC",
"reference_no": "123456",
"reference_date": "2013-02-14"
}
self.make_voucher_for_party(args, expected_outstanding)
args.update({
"party_type": "Supplier",
"received_or_paid": "Paid",
"supplier": "_Test Supplier 1",
"party_account": "_Test Supplier 1 - _TC"
})
expected_outstanding["Journal Voucher"] = [base_supplier_jv.name, 400.00]
self.make_voucher_for_party(args, expected_outstanding)
def create_voucher(self, test_record, args):
doc = frappe.copy_doc(test_record)
doc.update(args)
doc.insert()
doc.submit()
return doc
def create_against_jv(self, test_record, args):
jv = frappe.copy_doc(test_record)
jv.get("entries")[0].update(args)
if args.get("debit"):
jv.get("entries")[1].credit = args["debit"]
elif args.get("credit"):
jv.get("entries")[1].debit = args["credit"]
jv.insert()
jv.submit()
return jv
def make_voucher_for_party(self, args, expected_outstanding):
#Make Journal Voucher for Party
payment_tool_doc = frappe.new_doc("Payment Tool")
for k, v in args.items():
payment_tool_doc.set(k, v)
self.check_outstanding_vouchers(payment_tool_doc, args, expected_outstanding)
def check_outstanding_vouchers(self, doc, args, expected_outstanding):
from erpnext.accounts.doctype.payment_tool.payment_tool import get_outstanding_vouchers
outstanding_entries = get_outstanding_vouchers(json.dumps(args))
for d in outstanding_entries:
self.assertEquals(flt(d.get("outstanding_amount"), 2), expected_outstanding.get(d.get("voucher_type"))[1])
self.check_jv_entries(doc, outstanding_entries, expected_outstanding)
def check_jv_entries(self, paytool, outstanding_entries, expected_outstanding):
for e in outstanding_entries:
d1 = paytool.append("payment_tool_details")
d1.against_voucher_type = e.get("voucher_type")
d1.against_voucher_no = e.get("voucher_no")
d1.total_amount = e.get("invoice_amount")
d1.outstanding_amount = e.get("outstanding_amount")
d1.payment_amount = 100.00
paytool.total_payment_amount = 300
new_jv = paytool.make_journal_voucher()
#Create a list of expected values as [party account, payment against, against_jv, against_invoice,
#against_voucher, against_sales_order, against_purchase_order]
expected_values = [
[paytool.party_account, 100.00, expected_outstanding.get("Journal Voucher")[0], None, None, None, None],
[paytool.party_account, 100.00, None, expected_outstanding.get("Sales Invoice")[0], None, None, None],
[paytool.party_account, 100.00, None, None, expected_outstanding.get("Purchase Invoice")[0], None, None],
[paytool.party_account, 100.00, None, None, None, expected_outstanding.get("Sales Order")[0], None],
[paytool.party_account, 100.00, None, None, None, None, expected_outstanding.get("Purchase Order")[0]]
]
for jv_entry in new_jv.get("entries"):
if paytool.party_account == jv_entry.get("account"):
row = [
jv_entry.get("account"),
jv_entry.get("debit" if paytool.party_type=="Supplier" else "credit"),
jv_entry.get("against_jv"),
jv_entry.get("against_invoice"),
jv_entry.get("against_voucher"),
jv_entry.get("against_sales_order"),
jv_entry.get("against_purchase_order"),
]
self.assertTrue(row in expected_values)
self.assertEquals(new_jv.get("cheque_no"), paytool.reference_no)
self.assertEquals(new_jv.get("cheque_date"), paytool.reference_date)
def clear_table_entries(self):
frappe.db.sql("""delete from `tabGL Entry` where (account = "_Test Customer 3 - _TC" or account = "_Test Supplier 1 - _TC")""")
frappe.db.sql("""delete from `tabSales Order` where customer_name = "_Test Customer 3" """)
frappe.db.sql("""delete from `tabPurchase Order` where supplier_name = "_Test Supplier 1" """)

View File

@ -0,0 +1,130 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2014-08-11 14:27:54.463897",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "against_voucher_type",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Against Voucher Type",
"no_copy": 0,
"options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_width": "",
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"width": ""
},
{
"allow_on_submit": 0,
"fieldname": "against_voucher_no",
"fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Against Voucher No",
"no_copy": 0,
"options": "against_voucher_type",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "total_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Total Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "outstanding_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Outstanding Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"fieldname": "payment_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Payment Amount",
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2014-09-11 08:55:34.384017",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Tool Detail",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,9 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class PaymentToolDetail(Document):
pass

View File

@ -171,6 +171,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
@ -192,6 +193,7 @@
"read_only": 0
},
{
"allow_on_submit": 1,
"fieldname": "select_print_heading",
"fieldtype": "Link",
"in_filter": 0,
@ -205,7 +207,7 @@
],
"icon": "icon-cog",
"idx": 1,
"modified": "2014-06-23 16:40:59.510132",
"modified": "2014-09-09 05:35:31.969193",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Setting",

View File

@ -0,0 +1,10 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('POS Setting')
class TestPOSSetting(unittest.TestCase):
pass

View File

@ -0,0 +1 @@
[]

File diff suppressed because it is too large Load Diff

View File

@ -399,7 +399,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.027289",
"modified": "2014-09-09 05:35:35.712453",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@ -1,5 +1,4 @@
{
"allow_attach": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:05",
@ -1193,7 +1192,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-28 11:21:00.726344",
"modified": "2014-09-09 05:35:34.121045",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",

View File

@ -71,7 +71,9 @@ class SalesInvoice(SellingController):
self.is_opening = 'No'
self.set_aging_date()
frappe.get_doc("Account", self.debit_to).validate_due_date(self.posting_date, self.due_date)
self.set_against_income_account()
self.validate_c_form()
self.validate_time_logs_are_submitted()
@ -101,7 +103,6 @@ class SalesInvoice(SellingController):
if not cint(self.is_pos) == 1:
self.update_against_document_in_jv()
self.update_c_form()
self.update_time_log_batch(self.name)
convert_to_recurring(self, "RECINV.#####", self.posting_date)
@ -120,6 +121,7 @@ class SalesInvoice(SellingController):
self.update_status_updater_args()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.validate_c_form_on_cancel()
self.make_gl_entries_on_cancel()
@ -147,6 +149,10 @@ class SalesInvoice(SellingController):
validate_recurring_document(self)
convert_to_recurring(self, "RECINV.#####", self.posting_date)
def before_recurring(self):
self.aging_date = None
self.due_date = None
def get_portal_page(self):
return "invoice" if self.docstatus==1 else None
@ -376,6 +382,12 @@ class SalesInvoice(SellingController):
frappe.db.set(self, 'c_form_no', '')
def validate_c_form_on_cancel(self):
""" Display message if C-Form no exists on cancellation of Sales Invoice"""
if self.c_form_applicable == 'Yes' and self.c_form_no:
msgprint(_("Please remove this Invoice {0} from C-Form {1}")
.format(self.name, self.c_form_no), raise_exception = 1)
def update_current_stock(self):
for d in self.get('entries'):
if d.item_code and d.warehouse:
@ -584,14 +596,6 @@ class SalesInvoice(SellingController):
})
)
def update_c_form(self):
"""Update amended id in C-form"""
if self.c_form_no and self.amended_from:
frappe.db.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s,
invoice_date = %s, territory = %s, net_total = %s,
grand_total = %s where invoice_no = %s and parent = %s""",
(self.name, self.amended_from, self.c_form_no))
@frappe.whitelist()
def get_bank_cash_account(mode_of_payment):
val = frappe.db.get_value("Mode of Payment", mode_of_payment, "default_account")

View File

@ -439,7 +439,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.382092",
"modified": "2014-09-09 05:35:36.019576",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",

View File

@ -45,7 +45,7 @@ pscript['onload_Accounts Browser'] = function(wrapper){
'icon-plus');
}
wrapper.appframe.set_title_right('Refresh', function() {
wrapper.appframe.set_title_right(__('Refresh'), function() {
wrapper.$company_select.change();
});

View File

@ -1,7 +1,7 @@
frappe.pages['pos'].onload = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
title: 'Start POS',
title: __('Start POS'),
single_column: true
});

View File

@ -163,7 +163,7 @@ def create_party_account(party, party_type, company):
company_details = frappe.db.get_value("Company", company,
["abbr", "receivables_group", "payables_group"], as_dict=True)
if not frappe.db.exists("Account", (party + " - " + company_details.abbr)):
if not frappe.db.exists("Account", (party.strip() + " - " + company_details.abbr)):
parent_account = company_details.receivables_group \
if party_type=="Customer" else company_details.payables_group
if not parent_account:

View File

@ -67,12 +67,12 @@ def execute(filters=None):
def get_columns(supplier_naming_by):
columns = [
"Posting Date:Date:80", "Account:Link/Account:150", "Voucher Type::110",
"Voucher No::120", "::30", "Due Date:Date:80", "Bill No::80", "Bill Date:Date:80",
"Invoiced Amount:Currency:100", "Paid Amount:Currency:100",
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
"Supplier:Link/Supplier:150"
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150", _("Voucher Type") + "::110",
_("Voucher No") + "::120", "::30", _("Due Date") + ":Date:80", _("Bill No") + "::80", _("Bill Date") + ":Date:80",
_("Invoiced Amount") + ":Currency:100", _("Paid Amount") + ":Currency:100",
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100",
_("Supplier") + ":Link/Supplier:150"
]
if supplier_naming_by == "Naming Series":

View File

@ -20,13 +20,13 @@ class AccountsReceivableReport(object):
def get_columns(self, customer_naming_by):
columns = [
"Posting Date:Date:80", "Account:Link/Account:150",
"Voucher Type::110", "Voucher No::120", "::30",
"Due Date:Date:80",
"Invoiced Amount:Currency:100", "Payment Received:Currency:100",
"Outstanding Amount:Currency:100", "Age:Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100",
"Customer:Link/Customer:200"
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150",
_("Voucher Type") + "::110", _("Voucher No") + "::120", "::30",
_("Due Date") + ":Date:80",
_("Invoiced Amount") + ":Currency:100", _("Payment Received") + ":Currency:100",
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100",
_("Customer") + ":Link/Customer:200"
]
if customer_naming_by == "Naming Series":

View File

@ -14,9 +14,9 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Clearance Date:Date:110", "Against Account:Link/Account:200",
"Debit:Currency:120", "Credit:Currency:120"
return [_("Journal Voucher") + ":Link/Journal Voucher:140", _("Account") + ":Link/Account:140",
_("Posting Date") + ":Date:100", _("Clearance Date") + ":Date:110", _("Against Account") + ":Link/Account:200",
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120"
]
def get_conditions(filters):

View File

@ -16,31 +16,31 @@
</thead>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
{% if (data[i].posting_date) { %}
{% if (data[i][__("Posting Date")]) { %}
<tr>
<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
<td>{%= data[i].journal_voucher %}</td>
<td>{%= __("Against") %}: {%= data[i].against_account %}
{% if (data[i].reference) { %}
<br>{%= __("Reference") %}: {%= data[i].reference %}
{% if (data[i].ref_date) { %}
<br>{%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i].ref_date) %}
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Journal Voucher")] %}</td>
<td>{%= __("Against") %}: {%= data[i][__("Against Account")] %}
{% if (data[i][__("Reference")]) { %}
<br>{%= __("Reference") %}: {%= data[i][__("Reference")] %}
{% if (data[i][__("Ref Date")]) { %}
<br>{%= __("Reference Date") %}: {%= dateutil.str_to_user(data[i][__("Ref Date")]) %}
{% } %}
{% } %}
{% if (data[i].clearance_date) { %}
<br>{%= __("Clearance Date") %}: {%= dateutil.str_to_user(data[i].clearance_date) %}
{% if (data[i][__("Clearance Date")]) { %}
<br>{%= __("Clearance Date") %}: {%= dateutil.str_to_user(data[i][__("Clearance Date")]) %}
{% } %}
</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
</tr>
{% } else { %}
<tr>
<td></td>
<td></td>
<td>{%= data[i].journal_voucher %}</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
<td>{%= data[i][__("Journal Voucher")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
</tr>
{% } %}
{% } %}

View File

@ -26,7 +26,7 @@ def execute(filters=None):
amounts_not_reflected_in_system = frappe.db.sql("""select sum(ifnull(jvd.debit, 0) - ifnull(jvd.credit, 0))
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%s
and jv.posting_date > %s and jv.clearance_date <= %s
and jv.posting_date > %s and jv.clearance_date <= %s and ifnull(jv.is_opening, 'No') = 'No'
""", (filters["account"], filters["report_date"], filters["report_date"]))
amounts_not_reflected_in_system = flt(amounts_not_reflected_in_system[0][0]) \
@ -47,9 +47,9 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Posting Date:Date:100", "Journal Voucher:Link/Journal Voucher:220",
"Debit:Currency:120", "Credit:Currency:120",
"Against Account:Link/Account:200", "Reference::100", "Ref Date:Date:110", "Clearance Date:Date:110"
return [_("Posting Date") + ":Date:100", _("Journal Voucher") + ":Link/Journal Voucher:220",
_("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Against Account") + ":Link/Account:200", _("Reference") + "::100", _("Ref Date") + ":Date:110", _("Clearance Date") + ":Date:110"
]
def get_entries(filters):
@ -61,6 +61,7 @@ def get_entries(filters):
where jvd.parent = jv.name and jv.docstatus=1
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'
order by jv.name DESC""", filters, as_list=1)
return entries

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from frappe.utils import flt
from frappe.utils import formatdate
import time
from erpnext.accounts.utils import get_fiscal_year
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
@ -44,21 +45,21 @@ def get_columns(filters):
msgprint(_("Please specify") + ": " + label,
raise_exception=True)
columns = ["Cost Center:Link/Cost Center:120", "Account:Link/Account:120"]
columns = [_("Cost Center") + ":Link/Cost Center:120", _("Account") + ":Link/Account:120"]
group_months = False if filters["period"] == "Monthly" else True
for from_date, to_date in get_period_date_ranges(filters["period"], filters["fiscal_year"]):
for label in ["Target (%s)", "Actual (%s)", "Variance (%s)"]:
for label in [_("Target") + " (%s)", _("Actual") + " (%s)", _("Variance") + " (%s)"]:
if group_months:
label = label % (from_date.strftime("%b") + " - " + to_date.strftime("%b"))
label = label % (formatdate(from_date, format_string="MMM") + " - " + formatdate(from_date, format_string="MMM"))
else:
label = label % from_date.strftime("%b")
label = label % formatdate(from_date, format_string="MMM")
columns.append(label+":Float:120")
return columns + ["Total Target:Float:120", "Total Actual:Float:120",
"Total Variance:Float:120"]
return columns + [_("Total Target") + ":Float:120", _("Total Actual") + ":Float:120",
_("Total Variance") + ":Float:120"]
#Get cost center & target details
def get_costcenter_target_details(filters):

View File

@ -22,23 +22,23 @@
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
<tr>
{% if(data[i].posting_date) { %}
<td>{%= dateutil.str_to_user(data[i].posting_date) %}</td>
<td>{%= data[i].voucher_type%}
<br>{%= data[i].voucher_no %}</td>
<td>{%= data[i].account %}
<br>{%= __("Against") %}: {%= data[i].against_account %}
<br>{%= __("Remarks") %}: {%= data[i].remarks %}</td>
<td style="text-align: right">{%= format_currency(data[i].debit) %}</td>
<td style="text-align: right">{%= format_currency(data[i].credit) %}</td>
{% if(data[i][__("Posting Date")]) { %}
<td>{%= dateutil.str_to_user(data[i][__("Posting Date")]) %}</td>
<td>{%= data[i][__("Voucher Type")] %}
<br>{%= data[i][__("Voucher No")] %}</td>
<td>{%= data[i][__("Account")] %}
<br>{%= __("Against") %}: {%= data[i][__("Against Account")] %}
<br>{%= __("Remarks") %}: {%= data[i][__("Remarks")] %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">{%= format_currency(data[i][__("Credit")]) %}</td>
{% } else { %}
<td></td>
<td></td>
<td><b>{%= data[i].account || "&nbsp;" %}</b></td>
<td><b>{%= data[i][__("Account")] || "&nbsp;" %}</b></td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].debit) %}</td>
{%= data[i][__("Account")] && format_currency(data[i][__("Debit")]) %}</td>
<td style="text-align: right">
{%= data[i].account && format_currency(data[i].credit) %}</td>
{%= data[i][__("Account")] && format_currency(data[i][__("Credit")]) %}</td>
{% } %}
</tr>
{% } %}

View File

@ -34,9 +34,9 @@ def validate_filters(filters, account_details):
frappe.throw(_("From Date must be before To Date"))
def get_columns():
return ["Posting Date:Date:100", "Account:Link/Account:200", "Debit:Float:100",
"Credit:Float:100", "Voucher Type::120", "Voucher No::160", "Link::20",
"Against Account::120", "Cost Center:Link/Cost Center:100", "Remarks::400"]
return [_("Posting Date") + ":Date:100", _("Account") + ":Link/Account:200", _("Debit") + ":Float:100",
_("Credit") + ":Float:100", _("Voucher Type") + "::120", _("Voucher No") + "::160", _("Link") + "::20",
_("Against Account") + "::120", _("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400"]
def get_result(filters, account_details):
gl_entries = get_gl_entries(filters)

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from erpnext.stock.utils import get_buying_amount, get_sales_bom_buying_amount
@ -13,11 +14,11 @@ def execute(filters=None):
source = get_source_data(filters)
item_sales_bom = get_item_sales_bom()
columns = ["Delivery Note/Sales Invoice::120", "Link::30", "Posting Date:Date", "Posting Time",
"Item Code:Link/Item", "Item Name", "Description", "Warehouse:Link/Warehouse",
"Qty:Float", "Selling Rate:Currency", "Avg. Buying Rate:Currency",
"Selling Amount:Currency", "Buying Amount:Currency",
"Gross Profit:Currency", "Gross Profit %:Percent", "Project:Link/Project"]
columns = [__("Delivery Note/Sales Invoice") + "::120", _("Link") + "::30", _("Posting Date") + ":Date", _("Posting Time"),
_("Item Code") + ":Link/Item", _("Item Name"), _("Description"), _("Warehouse") + ":Link/Warehouse",
_("Qty") + ":Float", _("Selling Rate") + ":Currency", _("Avg. Buying Rate") + ":Currency",
_("Selling Amount") + ":Currency", _("Buying Amount") + ":Currency",
_("Gross Profit") + ":Currency", _("Gross Profit %") + ":Percent", _("Project") + ":Link/Project"]
data = []
for row in source:
selling_amount = flt(row.base_amount)

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe.utils import flt
def execute(filters=None):
@ -33,12 +34,12 @@ def execute(filters=None):
def get_columns():
return ["Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Customer:120",
"Supplier Account:Link/Account:120", "Project:Link/Project:80", "Company:Link/Company:100",
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100",
"Expense Account:Link/Account:140", "Qty:Float:120", "Rate:Currency:120",
"Amount:Currency:120"]
return [_("Item Code") + ":Link/Item:120", _("Item Name") + "::120", _("Item Group") + ":Link/Item Group:100",
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80", _("Supplier") + ":Link/Customer:120",
_("Supplier Account") + ":Link/Account:120", _("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100",
_("Purchase Order") + ":Link/Purchase Order:100", _("Purchase Receipt") + ":Link/Purchase Receipt:100",
_("Expense Account") + ":Link/Account:140", _("Qty") + ":Float:120", _("Rate") + ":Currency:120",
_("Amount") + ":Currency:120"]
def get_conditions(filters):
conditions = ""

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import msgprint, _
from frappe.utils import flt
def execute(filters=None):
@ -32,12 +33,12 @@ def execute(filters=None):
def get_columns():
return [
"Item Code:Link/Item:120", "Item Name::120", "Item Group:Link/Item Group:100",
"Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer:Link/Customer:120",
"Customer Account:Link/Account:120", "Territory:Link/Territory:80",
"Project:Link/Project:80", "Company:Link/Company:100", "Sales Order:Link/Sales Order:100",
"Delivery Note:Link/Delivery Note:100", "Income Account:Link/Account:140",
"Qty:Float:120", "Rate:Currency:120", "Amount:Currency:120"
_("Item Code") + ":Link/Item:120", _("Item Name") + "::120", _("Item Group") + ":Link/Item Group:100",
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80", _("Customer") + ":Link/Customer:120",
_("Customer Account") + ":Link/Account:120", _("Territory") + ":Link/Territory:80",
_("Project") + ":Link/Project:80", _("Company") + ":Link/Company:100", _("Sales Order") + ":Link/Sales Order:100",
_("Delivery Note") + ":Link/Delivery Note:100", _("Income Account") + ":Link/Account:140",
_("Qty") + ":Float:120", _("Rate") + ":Currency:120", _("Amount") + ":Currency:120"
]
def get_conditions(filters):

View File

@ -37,11 +37,11 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130",
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
return [_("Journal Voucher") + ":Link/Journal Voucher:140", _("Account") + ":Link/Account:140",
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
_("Against Invoice Posting Date") + ":Date:130", _("Debit") + ":Currency:120", _("Credit") + ":Currency:120",
_("Reference No") + "::100", _("Reference Date") + ":Date:100", _("Remarks") + "::150", _("Age") +":Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100"
]
def get_conditions(filters):

View File

@ -63,11 +63,11 @@ def execute(filters=None):
def get_columns(invoice_list):
"""return columns based on filters"""
columns = [
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier Id::120",
"Supplier Name::120", "Supplier Account:Link/Account:120",
"Account Group:LInk/Account:120", "Project:Link/Project:80", "Bill No::120",
"Bill Date:Date:80", "Remarks::150",
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100"
_("Invoice") + ":Link/Purchase Invoice:120", _("Posting Date") + ":Date:80", _("Supplier Id") + "::120",
_("Supplier Name") + "::120", _("Supplier Account") + ":Link/Account:120",
_("Account Group") + ":Link/Account:120", _("Project") + ":Link/Project:80", _("Bill No") + "::120",
_("Bill Date") + ":Date:80", _("Remarks") + "::150",
_("Purchase Order") + ":Link/Purchase Order:100", _("Purchase Receipt") + ":Link/Purchase Receipt:100"
]
expense_accounts = tax_accounts = expense_columns = tax_columns = []

View File

@ -63,10 +63,10 @@ def execute(filters=None):
def get_columns(invoice_list):
"""return columns based on filters"""
columns = [
"Invoice:Link/Sales Invoice:120", "Posting Date:Date:80", "Customer Id::120",
"Customer Name::120", "Customer Account:Link/Account:120", "Account Group:LInk/Account:120",
"Territory:Link/Territory:80", "Project:Link/Project:80", "Remarks::150",
"Sales Order:Link/Sales Order:100", "Delivery Note:Link/Delivery Note:100"
_("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80", _("Customer Id") + "::120",
_("Customer Name") + "::120", _("Customer Account") + ":Link/Account:120", _("Account Group") + ":Link/Account:120",
_("Territory") + ":Link/Territory:80", _("Project") + ":Link/Project:80", _("Remarks") + "::150",
_("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100"
]
income_accounts = tax_accounts = income_columns = tax_columns = []

View File

@ -391,3 +391,42 @@ def get_stock_rbnb_difference(posting_date, company):
# Amount should be credited
return flt(stock_rbnb) + flt(sys_bal)
def get_outstanding_invoices(amount_query, account):
all_outstanding_vouchers = []
outstanding_voucher_list = frappe.db.sql("""
select
voucher_no, voucher_type, posting_date,
ifnull(sum({amount_query}), 0) as invoice_amount
from
`tabGL Entry`
where
account = %s and {amount_query} > 0
group by voucher_type, voucher_no
""".format(amount_query = amount_query), account, as_dict = True)
for d in outstanding_voucher_list:
payment_amount = frappe.db.sql("""
select ifnull(sum(ifnull({amount_query}, 0)), 0)
from
`tabGL Entry`
where
account = %s and {amount_query} < 0
and against_voucher_type = %s and ifnull(against_voucher, '') = %s
""".format(**{
"amount_query": amount_query
}), (account, d.voucher_type, d.voucher_no))
payment_amount = -1*payment_amount[0][0] if payment_amount else 0
if d.invoice_amount > payment_amount:
all_outstanding_vouchers.append({
'voucher_no': d.voucher_no,
'voucher_type': d.voucher_type,
'posting_date': d.posting_date,
'invoice_amount': flt(d.invoice_amount),
'outstanding_amount': d.invoice_amount - payment_amount
})
return all_outstanding_vouchers

File diff suppressed because it is too large Load Diff

View File

@ -238,6 +238,11 @@ def make_purchase_receipt(source_name, target_doc=None):
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
def postprocess(source, target):
set_missing_values(source, target)
#Get the advance paid Journal Vouchers in Purchase Invoice Advance
target.get_advances()
def update_item(obj, target, source_parent):
target.amount = flt(obj.amount) - flt(obj.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
@ -263,6 +268,6 @@ def make_purchase_invoice(source_name, target_doc=None):
"doctype": "Purchase Taxes and Charges",
"add_if_empty": True
}
}, target_doc, set_missing_values)
}, target_doc, postprocess)
return doc

View File

@ -1,5 +1,6 @@
[
{
"advance_paid": 0.0,
"buying_price_list": "_Test Price List",
"company": "_Test Company",
"conversion_rate": 1.0,
@ -31,5 +32,39 @@
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
},
{
"advance_paid": 0.0,
"buying_price_list": "_Test Price List",
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",
"doctype": "Purchase Order",
"fiscal_year": "_Test Fiscal Year 2013",
"grand_total": 5000.0,
"grand_total_import": 5000.0,
"is_subcontracted": "No",
"naming_series": "_T-Purchase Order-",
"net_total": 5000.0,
"po_details": [
{
"base_amount": 5000.0,
"conversion_factor": 1.0,
"description": "_Test Item",
"doctype": "Purchase Order Item",
"item_code": "_Test Item",
"item_name": "_Test Item",
"parentfield": "po_details",
"qty": 10.0,
"rate": 500.0,
"schedule_date": "2013-03-01",
"stock_uom": "_Test UOM",
"uom": "_Test UOM",
"warehouse": "_Test Warehouse - _TC"
}
],
"supplier": "_Test Supplier",
"supplier_name": "_Test Supplier",
"transaction_date": "2013-02-12"
}
]
]

View File

@ -445,7 +445,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.684601",
"modified": "2014-09-09 05:35:36.346557",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",

View File

@ -186,12 +186,20 @@
],
"icon": "icon-user",
"idx": 1,
"modified": "2014-08-26 04:55:32.004458",
"modified": "2014-09-10 17:53:09.286715",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier",
"owner": "Administrator",
"permissions": [
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User"
},
{
"amend": 0,
"create": 0,
@ -201,7 +209,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "Purchase User",
"role": "Purchase Manager",
"submit": 0,
"write": 0
},
@ -224,11 +232,27 @@
"read": 1,
"role": "Material User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Material Manager"
},
{
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"role": "Accounts User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager"
}
],
"search_fields": "supplier_name,supplier_type",

View File

@ -4,5 +4,11 @@
"doctype": "Supplier",
"supplier_name": "_Test Supplier",
"supplier_type": "_Test Supplier Type"
},
{
"company": "_Test Company",
"doctype": "Supplier",
"supplier_name": "_Test Supplier 1",
"supplier_type": "_Test Supplier Type"
}
]
]

View File

@ -1,5 +1,5 @@
{
"allow_import": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:45",
"docstatus": 0,
@ -575,7 +575,7 @@
"icon": "icon-shopping-cart",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-14 02:17:26.401532",
"modified": "2014-09-09 05:35:35.369734",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation",

View File

@ -331,7 +331,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:30.976906",
"modified": "2014-09-09 05:35:36.623995",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",

View File

@ -5,12 +5,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
"modified": "2014-06-03 07:18:17.358554",
"modified_by": "Administrator",
"modified": "2014-09-11 08:53:17.358554",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Addresses and Contacts",
"owner": "Administrator",
"query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
"query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as \"Contact Name::180\",\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
"ref_doctype": "Supplier",
"report_name": "Supplier Addresses and Contacts",
"report_type": "Query Report"

View File

@ -61,6 +61,11 @@ def get_data():
"name": "Period Closing Voucher",
"description": _("Close Balance Sheet and book Profit or Loss.")
},
{
"type": "doctype",
"name": "Payment Tool",
"description": _("Create Payment Entries against Orders or Invoices.")
},
]
},
{

View File

@ -135,12 +135,6 @@ def get_data():
"name": "Item-wise Purchase History",
"doctype": "Item"
},
{
"type": "report",
"is_query_report": True,
"name": "Item-wise Last Purchase Rate",
"doctype": "Item"
},
{
"type": "report",
"is_query_report": True,

View File

@ -171,6 +171,12 @@ def get_data():
"label": _("Stock Analytics"),
"icon": "icon-bar-chart"
},
{
"type": "report",
"is_query_report": True,
"name": "Warehouse-Wise Stock Balance",
"doctype": "Warehouse"
},
]
},
{
@ -222,12 +228,6 @@ def get_data():
"name": "Batch-Wise Balance History",
"doctype": "Batch"
},
{
"type": "report",
"is_query_report": True,
"name": "Warehouse-Wise Stock Balance",
"doctype": "Warehouse"
},
{
"type": "report",
"is_query_report": True,

View File

@ -363,9 +363,10 @@ class AccountsController(TransactionBase):
and ifnull(allocated_amount, 0) = 0""" % (childtype, '%s', '%s'), (parentfield, self.name))
def get_advances(self, account_head, child_doctype, parentfield, dr_or_cr):
against_order_list = []
res = frappe.db.sql("""
select
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no
t1.name as jv_no, t1.remark, t2.%s as amount, t2.name as jv_detail_no, t2.%s as order_no
from
`tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
where
@ -374,18 +375,25 @@ class AccountsController(TransactionBase):
and ifnull(t2.against_invoice, '') = ''
and ifnull(t2.against_jv, '') = ''
order by t1.posting_date""" %
(dr_or_cr, '%s'), account_head, as_dict=1)
(dr_or_cr, "against_sales_order" if dr_or_cr == "credit" \
else "against_purchase_order", '%s'),
account_head, as_dict= True)
if self.get("entries"):
for i in self.get("entries"):
against_order_list.append(i.sales_order if dr_or_cr == "credit" else i.purchase_order)
self.set(parentfield, [])
for d in res:
self.append(parentfield, {
"doctype": child_doctype,
"journal_voucher": d.jv_no,
"jv_detail_no": d.jv_detail_no,
"remarks": d.remark,
"advance_amount": flt(d.amount),
"allocate_amount": 0
})
if not against_order_list or d.order_no in against_order_list:
self.append(parentfield, {
"doctype": child_doctype,
"journal_voucher": d.jv_no,
"jv_detail_no": d.jv_detail_no,
"remarks": d.remark,
"advance_amount": flt(d.amount),
"allocate_amount": 0
})
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
from erpnext.controllers.status_updater import get_tolerance_for
@ -430,6 +438,32 @@ class AccountsController(TransactionBase):
return stock_items
def set_total_advance_paid(self):
if self.doctype == "Sales Order":
dr_or_cr = "credit"
against_field = "against_sales_order"
else:
dr_or_cr = "debit"
against_field = "against_purchase_order"
advance_paid = frappe.db.sql("""
select
sum(ifnull({dr_or_cr}, 0))
from
`tabJournal Voucher Detail`
where
{against_field} = %s and docstatus = 1 and is_advance = "Yes" """.format(dr_or_cr=dr_or_cr, \
against_field=against_field), self.name)
if advance_paid:
advance_paid = flt(advance_paid[0][0], self.precision("advance_paid"))
if flt(self.grand_total) >= advance_paid:
frappe.db.set_value(self.doctype, self.name, "advance_paid", advance_paid)
else:
frappe.throw(_("Total advance ({0}) against Order {1} cannot be greater \
than the Grand Total ({2})")
.format(advance_paid, self.name, self.grand_total))
@property
def company_abbr(self):
if not hasattr(self, "_abbr"):

View File

@ -36,6 +36,9 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
% (doctype, date_field, '%s', '%s'), (next_date, recurring_id)):
try:
ref_wrapper = frappe.get_doc(doctype, ref_document)
if hasattr(ref_wrapper, "before_recurring"):
ref_wrapper.before_recurring()
new_document_wrapper = make_new_document(ref_wrapper, date_field, next_date)
send_notification(new_document_wrapper)
if commit:

View File

@ -16,10 +16,10 @@ def get_columns(filters, trans):
# get conditions for grouping filter cond
group_by_cols = group_wise_column(filters.get("group_by"))
columns = based_on_details["based_on_cols"] + period_cols + ["Total(Qty):Float:120", "Total(Amt):Currency:120"]
columns = based_on_details["based_on_cols"] + period_cols + [_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
if group_by_cols:
columns = based_on_details["based_on_cols"] + group_by_cols + period_cols + \
["Total(Qty):Float:120", "Total(Amt):Currency:120"]
[_("Total(Qty)") + ":Float:120", _("Total(Amt)") + ":Currency:120"]
conditions = {"based_on_select": based_on_details["based_on_select"], "period_wise_select": period_select,
"columns": columns, "group_by": based_on_details["based_on_group_by"], "grbc": group_by_cols, "trans": trans,
@ -130,8 +130,8 @@ def period_wise_columns_query(filters, trans):
get_period_wise_columns(dt, filters.get("period"), pwc)
query_details = get_period_wise_query(dt, trans_date, query_details)
else:
pwc = [filters.get("fiscal_year") + " (Qty):Float:120",
filters.get("fiscal_year") + " (Amt):Currency:120"]
pwc = [_(filters.get("fiscal_year")) + " ("+_("Qty") + "):Float:120",
_(filters.get("fiscal_year")) + " ("+ _("Amt") + "):Currency:120"]
query_details = " SUM(t2.qty), SUM(t2.base_amount),"
query_details += 'SUM(t2.qty), SUM(t2.base_amount)'
@ -139,11 +139,11 @@ def period_wise_columns_query(filters, trans):
def get_period_wise_columns(bet_dates, period, pwc):
if period == 'Monthly':
pwc += [get_mon(bet_dates[0]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + " (Amt):Currency:120"]
pwc += [_(get_mon(bet_dates[0])) + " (" + _("Qty") + "):Float:120",
_(get_mon(bet_dates[0])) + " (" + _("Amt") + "):Currency:120"]
else:
pwc += [get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Qty):Float:120",
get_mon(bet_dates[0]) + "-" + get_mon(bet_dates[1]) + " (Amt):Currency:120"]
pwc += [_(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Qty") + "):Float:120",
_(get_mon(bet_dates[0])) + "-" + _(get_mon(bet_dates[1])) + " (" + _("Amt") + "):Currency:120"]
def get_period_wise_query(bet_dates, trans_date, query_details):
query_details += """SUM(IF(t1.%(trans_date)s BETWEEN '%(sd)s' AND '%(ed)s', t2.qty, NULL)),

View File

@ -20,7 +20,7 @@ frappe.pages['activity'].onload = function(wrapper) {
});
list.run();
wrapper.appframe.set_title_right("Refresh", function() { list.run(); });
wrapper.appframe.set_title_right(__("Refresh"), function() { list.run(); });
// Build Report Button
if(frappe.boot.user.can_get_report.indexOf("Feed")!=-1) {

View File

@ -4,7 +4,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "4.3.0"
app_version = "4.4.0"
error_report_email = "support@erpnext.com"

File diff suppressed because it is too large Load Diff

View File

@ -200,7 +200,7 @@ def validate_employee_role(doc, method):
# called via User hook
if "Employee" in [d.role for d in doc.get("user_roles")]:
if not frappe.db.get_value("Employee", {"user_id": doc.name}):
frappe.msgprint("Please set User ID field in an Employee record to set Employee Role")
frappe.msgprint(_("Please set User ID field in an Employee record to set Employee Role"))
doc.get("user_roles").remove(doc.get("user_roles", {"role": "Employee"})[0])
def update_user_permissions(doc, method):

View File

@ -158,6 +158,7 @@
"reqd": 1
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@ -183,7 +184,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 3,
"modified": "2014-08-28 03:32:38.865202",
"modified": "2014-09-09 05:35:31.531651",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",

View File

@ -72,6 +72,7 @@
"search_index": 0
},
{
"allow_on_submit": 1,
"fieldname": "letter_head",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@ -336,7 +337,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2014-08-27 06:38:10.006224",
"modified": "2014-09-09 05:35:33.807228",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip",

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
def execute(filters=None):
@ -15,9 +16,9 @@ def execute(filters=None):
def get_columns():
return [
"Employee:Link/Employee:120", "Name:Data:200", "Date of Birth:Date:100",
"Branch:Link/Branch:120", "Department:Link/Department:120",
"Designation:Link/Designation:120", "Gender::60", "Company:Link/Company:120"
_("Employee") + ":Link/Employee:120", _("Name") + ":Data:200", _("Date of Birth")+ ":Date:100",
_("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120",
_("Designation") + ":Link/Designation:120", _("Gender") + "::60", _("Company") + ":Link/Company:120"
]
def get_employees(filters):

View File

@ -39,13 +39,13 @@ def execute(filters=None):
','.join(['%s']*len(employee_names)), employee_names, as_dict=True)
columns = [
"Fiscal Year", "Employee:Link/Employee:150", "Employee Name::200", "Department::150"
_("Fiscal Year"), _("Employee") + ":Link/Employee:150", _("Employee Name") + "::200", _("Department") +"::150"
]
for leave_type in leave_types:
columns.append(leave_type + " Allocated:Float")
columns.append(leave_type + " Taken:Float")
columns.append(leave_type + " Balance:Float")
columns.append(_(leave_type) + " " + _("Allocated") + ":Float")
columns.append(_(leave_type) + " " + _("Taken") + ":Float")
columns.append(_(leave_type) + " " + _("Balance") + ":Float")
data = {}
for d in allocations:

View File

@ -45,15 +45,15 @@ def execute(filters=None):
def get_columns(filters):
columns = [
"Employee:Link/Employee:120", "Employee Name::140", "Branch:Link/Branch:120",
"Department:Link/Department:120", "Designation:Link/Designation:120",
"Company:Link/Company:120"
_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch")+ ":Link/Branch:120",
_("Department") + ":Link/Department:120", _("Designation") + ":Link/Designation:120",
_("Company") + ":Link/Company:120"
]
for day in range(filters["total_days_in_month"]):
columns.append(cstr(day+1) +"::20")
columns += ["Total Present:Float:80", "Total Absent:Float:80"]
columns += [_("Total Present") + ":Float:80", _("Total Absent") + ":Float:80"]
return columns
def get_attendance_list(conditions, filters):

View File

@ -36,10 +36,10 @@ def execute(filters=None):
def get_columns(salary_slips):
columns = [
"Employee:Link/Employee:120", "Employee Name::140", "Branch:Link/Branch:120",
"Department:Link/Department:120", "Designation:Link/Designation:120",
"Company:Link/Company:120", "Month::80", "Leave Without pay:Float:130",
"Payment Days:Float:120"
_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:120",
_("Department") + ":Link/Department:120", _("Designation") + ":Link/Designation:120",
_("Company") + ":Link/Company:120", _("Month") + "::80", _("Leave Without Pay") + ":Float:130",
_("Payment Days") + ":Float:120"
]
earning_types = frappe.db.sql_list("""select distinct e_type from `tabSalary Slip Earning`

View File

@ -66,7 +66,10 @@ cur_frm.cscript.workstation = function(doc,dt,dn) {
frappe.model.with_doc("Workstation", d.workstation, function(name, r) {
d.hour_rate = r.docs[0].hour_rate;
refresh_field("hour_rate", dn, "bom_operations");
d.fixed_cycle_cost = r.docs[0].fixed_cycle_cost;
refresh_field("fixed_cycle_cost", dn, "bom_operations");
erpnext.bom.calculate_op_cost(doc);
erpnext.bom.calculate_fixed_cost(doc);
erpnext.bom.calculate_total(doc);
});
}
@ -74,6 +77,7 @@ cur_frm.cscript.workstation = function(doc,dt,dn) {
cur_frm.cscript.hour_rate = function(doc, dt, dn) {
erpnext.bom.calculate_op_cost(doc);
erpnext.bom.calculate_fixed_cost(doc);
erpnext.bom.calculate_total(doc);
}
@ -116,7 +120,6 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
}
}
cur_frm.cscript.qty = function(doc, cdt, cdn) {
erpnext.bom.calculate_rm_cost(doc);
erpnext.bom.calculate_total(doc);
@ -145,6 +148,15 @@ erpnext.bom.calculate_op_cost = function(doc) {
refresh_field('operating_cost');
}
erpnext.bom.calculate_fixed_cost = function(doc) {
var op = doc.bom_operations || [];
var total_fixed_cost = 0;
for(var i=0;i<op.length;i++) {
total_fixed_cost += flt(op[i].fixed_cycle_cost);
}
cur_frm.set_value("total_fixed_cost", total_fixed_cost);
}
erpnext.bom.calculate_rm_cost = function(doc) {
var rm = doc.bom_materials || [];
total_rm_cost = 0;
@ -155,14 +167,15 @@ erpnext.bom.calculate_rm_cost = function(doc) {
{'qty_consumed_per_unit': flt(rm[i].qty)/flt(doc.quantity)}, 'bom_materials');
total_rm_cost += amt;
}
doc.raw_material_cost = total_rm_cost;
refresh_field('raw_material_cost');
cur_frm.set_value("raw_material_cost", total_rm_cost);
}
// Calculate Total Cost
erpnext.bom.calculate_total = function(doc) {
doc.total_cost = flt(doc.raw_material_cost) + flt(doc.operating_cost);
doc.total_variable_cost = flt(doc.raw_material_cost) + flt(doc.operating_cost) ;
refresh_field('total_variable_cost');
doc.total_cost = flt(doc.total_fixed_cost) + flt(doc.total_variable_cost);
refresh_field('total_cost');
}
@ -204,5 +217,7 @@ cur_frm.fields_dict['bom_materials'].grid.get_field('bom_no').get_query = functi
cur_frm.cscript.validate = function(doc, dt, dn) {
erpnext.bom.calculate_op_cost(doc);
erpnext.bom.calculate_rm_cost(doc);
erpnext.bom.calculate_fixed_cost(doc);
erpnext.bom.calculate_total(doc);
}

View File

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_attach": 0,
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 0,
"creation": "2013-01-22 15:11:38",
@ -86,6 +87,7 @@
{
"fieldname": "bom_operations",
"fieldtype": "Table",
"in_list_view": 0,
"label": "BOM Operations",
"oldfieldname": "bom_operations",
"oldfieldtype": "Table",
@ -115,19 +117,6 @@
"oldfieldtype": "Section Break",
"permlevel": 0
},
{
"fieldname": "total_cost",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Total Cost",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "cb1",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "raw_material_cost",
"fieldtype": "Float",
@ -142,6 +131,33 @@
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "cb1",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "total_variable_cost",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Total Variable Cost",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "total_fixed_cost",
"fieldtype": "Float",
"label": "Total Fixed Cost",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "total_cost",
"fieldtype": "Float",
"label": "Total Cost",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "more_info_section",
"fieldtype": "Section Break",
@ -232,7 +248,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"modified": "2014-05-27 03:49:08.024523",
"modified": "2014-09-08 16:30:46.265762",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@ -127,7 +127,7 @@ class BOM(Document):
self.save()
def get_bom_unitcost(self, bom_no):
bom = frappe.db.sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
bom = frappe.db.sql("""select name, total_variable_cost/quantity as unit_cost from `tabBOM`
where is_active = 1 and name = %s""", bom_no, as_dict=1)
return bom and bom[0]['unit_cost'] or 0
@ -269,7 +269,8 @@ class BOM(Document):
"""Calculate bom totals"""
self.calculate_op_cost()
self.calculate_rm_cost()
self.total_cost = self.raw_material_cost + self.operating_cost
self.calculate_fixed_cost()
self.total_variable_cost = self.raw_material_cost + self.operating_cost
def calculate_op_cost(self):
"""Update workstation rate and calculates totals"""
@ -282,6 +283,15 @@ class BOM(Document):
total_op_cost += flt(d.operating_cost)
self.operating_cost = total_op_cost
def calculate_fixed_cost(self):
"""Update workstation rate and calculates totals"""
fixed_cost = 0
for d in self.get('bom_operations'):
if d.workstation:
fixed_cost += flt(frappe.db.get_value("Workstation", d.workstation, "fixed_cycle_cost"))
self.total_fixed_cost = fixed_cost
def calculate_rm_cost(self):
"""Fetch RM rate as per today's valuation rate and calculate totals"""
total_rm_cost = 0

View File

@ -15,6 +15,6 @@
</div>
</div>
<div class="col-xs-2 text-right">
{%= doc.get_formatted("total_cost") %}
{%= doc.get_formatted("total_variable_cost") %}
</div>
</div>

View File

@ -1,3 +1,3 @@
frappe.listview_settings['BOM'] = {
add_fields: ["is_active", "is_default", "total_cost"]
add_fields: ["is_active", "is_default", "total_variable_cost"]
};

View File

@ -54,10 +54,20 @@
"is_default": 1,
"item": "_Test FG Item",
"quantity": 1.0
},
},
{
"bom_operations": [
{
"operation_no": "1",
"opn_description": "_Test",
"workstation": "_Test Workstation 1",
"time_in_min": 60,
"operating_cost": 100
}
],
"bom_materials": [
{
"operation_no": 1,
"amount": 5000.0,
"doctype": "BOM Item",
"item_code": "_Test Item",
@ -67,6 +77,7 @@
"stock_uom": "_Test UOM"
},
{
"operation_no": 1,
"amount": 2000.0,
"bom_no": "BOM/_Test Item Home Desktop Manufactured/001",
"doctype": "BOM Item",
@ -82,6 +93,7 @@
"is_active": 1,
"is_default": 1,
"item": "_Test FG Item 2",
"quantity": 1.0
"quantity": 1.0,
"with_operations": 1
}
]

View File

@ -1,81 +1,89 @@
{
"creation": "2013-02-22 01:27:49.000000",
"docstatus": 0,
"doctype": "DocType",
"creation": "2013-02-22 01:27:49",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "operation_no",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Operation No",
"oldfieldname": "operation_no",
"oldfieldtype": "Data",
"permlevel": 0,
"fieldname": "operation_no",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Operation No",
"oldfieldname": "operation_no",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "opn_description",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Operation Description",
"oldfieldname": "opn_description",
"oldfieldtype": "Text",
"permlevel": 0,
"fieldname": "opn_description",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Operation Description",
"oldfieldname": "opn_description",
"oldfieldtype": "Text",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "col_break1",
"fieldtype": "Column Break",
"fieldname": "col_break1",
"fieldtype": "Column Break",
"permlevel": 0
},
},
{
"fieldname": "workstation",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Workstation",
"oldfieldname": "workstation",
"oldfieldtype": "Link",
"options": "Workstation",
"permlevel": 0,
"fieldname": "workstation",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Workstation",
"oldfieldname": "workstation",
"oldfieldtype": "Link",
"options": "Workstation",
"permlevel": 0,
"reqd": 0
},
},
{
"fieldname": "hour_rate",
"fieldtype": "Float",
"in_list_view": 0,
"label": "Hour Rate",
"oldfieldname": "hour_rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "hour_rate",
"fieldtype": "Float",
"in_list_view": 0,
"label": "Hour Rate",
"oldfieldname": "hour_rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 0
},
},
{
"fieldname": "time_in_mins",
"fieldtype": "Float",
"in_list_view": 0,
"label": "Operation Time (mins)",
"oldfieldname": "time_in_mins",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "time_in_mins",
"fieldtype": "Float",
"in_list_view": 0,
"label": "Operation Time (mins)",
"oldfieldname": "time_in_mins",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 0
},
},
{
"allow_on_submit": 0,
"fieldname": "operating_cost",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Operating Cost",
"oldfieldname": "operating_cost",
"oldfieldtype": "Currency",
"permlevel": 0,
"allow_on_submit": 0,
"fieldname": "operating_cost",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Operating Cost",
"oldfieldname": "operating_cost",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "fixed_cycle_cost",
"fieldtype": "Float",
"in_list_view": 0,
"label": "Fixed Cycle Cost",
"permlevel": 0
}
],
"idx": 1,
"istable": 1,
"modified": "2014-02-03 12:53:03.000000",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
"owner": "Administrator"
}
],
"idx": 1,
"istable": 1,
"modified": "2014-09-15 12:03:47.456370",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
"owner": "Administrator",
"permissions": []
}

View File

@ -25,7 +25,7 @@ class BOMReplaceTool(Document):
frappe.throw(_("Current BOM and New BOM can not be same"))
def update_new_bom(self):
current_bom_unitcost = frappe.db.sql("""select total_cost/quantity
current_bom_unitcost = frappe.db.sql("""select total_variable_cost/quantity
from `tabBOM` where name = %s""", self.current_bom)
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,

View File

@ -123,3 +123,5 @@ cur_frm.set_query("bom_no", function(doc) {
}
} else msgprint(__("Please enter Production Item first"));
});
cur_frm.add_fetch('bom_no', 'total_fixed_cost', 'total_fixed_cost');

View File

@ -1,257 +1,264 @@
{
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:16",
"docstatus": 0,
"doctype": "DocType",
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:16",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "item",
"fieldtype": "Section Break",
"label": "Item",
"options": "icon-gift",
"fieldname": "item",
"fieldtype": "Section Break",
"label": "Item",
"options": "icon-gift",
"permlevel": 0
},
},
{
"default": "PRO-",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"options": "PRO-",
"permlevel": 0,
"default": "PRO-",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
"options": "PRO-",
"permlevel": 0,
"reqd": 1
},
},
{
"depends_on": "eval:!doc.__islocal",
"fieldname": "status",
"fieldtype": "Select",
"in_filter": 1,
"in_list_view": 1,
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled",
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"depends_on": "eval:!doc.__islocal",
"fieldname": "status",
"fieldtype": "Select",
"in_filter": 1,
"in_list_view": 1,
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled",
"permlevel": 0,
"read_only": 1,
"reqd": 1,
"search_index": 1
},
},
{
"fieldname": "production_item",
"fieldtype": "Link",
"in_filter": 1,
"in_list_view": 1,
"label": "Item To Manufacture",
"oldfieldname": "production_item",
"oldfieldtype": "Link",
"options": "Item",
"permlevel": 0,
"read_only": 0,
"fieldname": "production_item",
"fieldtype": "Link",
"in_filter": 1,
"in_list_view": 1,
"label": "Item To Manufacture",
"oldfieldname": "production_item",
"oldfieldtype": "Link",
"options": "Item",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
},
{
"depends_on": "production_item",
"description": "Bill of Material to be considered for manufacturing",
"fieldname": "bom_no",
"fieldtype": "Link",
"in_list_view": 1,
"label": "BOM No",
"oldfieldname": "bom_no",
"oldfieldtype": "Link",
"options": "BOM",
"permlevel": 0,
"read_only": 0,
"depends_on": "production_item",
"description": "Bill of Material to be considered for manufacturing",
"fieldname": "bom_no",
"fieldtype": "Link",
"in_list_view": 1,
"label": "BOM No",
"oldfieldname": "bom_no",
"oldfieldtype": "Link",
"options": "BOM",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
},
{
"default": "1",
"description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
"fieldname": "use_multi_level_bom",
"fieldtype": "Check",
"label": "Use Multi-Level BOM",
"default": "1",
"description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
"fieldname": "use_multi_level_bom",
"fieldtype": "Check",
"label": "Use Multi-Level BOM",
"permlevel": 0
},
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"read_only": 0,
"fieldname": "column_break1",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"permlevel": 0,
"read_only": 0,
"width": "50%"
},
},
{
"description": "Manufacture against Sales Order",
"fieldname": "sales_order",
"fieldtype": "Link",
"label": "Sales Order",
"options": "Sales Order",
"permlevel": 0,
"description": "Manufacture against Sales Order",
"fieldname": "sales_order",
"fieldtype": "Link",
"label": "Sales Order",
"options": "Sales Order",
"permlevel": 0,
"read_only": 0
},
},
{
"depends_on": "production_item",
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty To Manufacture",
"oldfieldname": "qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 0,
"depends_on": "production_item",
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty To Manufacture",
"oldfieldname": "qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
},
{
"depends_on": "eval:doc.docstatus==1",
"description": "Automatically updated via Stock Entry of type Manufacture/Repack",
"fieldname": "produced_qty",
"fieldtype": "Float",
"label": "Manufactured Qty",
"no_copy": 1,
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 1
},
{
"depends_on": "sales_order",
"fieldname": "expected_delivery_date",
"fieldtype": "Date",
"label": "Expected Delivery Date",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "warehouses",
"fieldtype": "Section Break",
"label": "Warehouses",
"options": "icon-building",
"depends_on": "production_item",
"fieldname": "total_fixed_cost",
"fieldtype": "Float",
"label": "Total Fixed Cost",
"permlevel": 0
},
},
{
"depends_on": "production_item",
"description": "Manufactured quantity will be updated in this warehouse",
"fieldname": "fg_warehouse",
"fieldtype": "Link",
"in_list_view": 0,
"label": "For Warehouse",
"options": "Warehouse",
"permlevel": 0,
"read_only": 0,
"reqd": 0
},
{
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"label": "Work-in-Progress Warehouse",
"options": "Warehouse",
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"options": "icon-file-text",
"permlevel": 0,
"read_only": 0
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Item Description",
"permlevel": 0,
"depends_on": "eval:doc.docstatus==1",
"description": "Automatically updated via Stock Entry of type Manufacture/Repack",
"fieldname": "produced_qty",
"fieldtype": "Float",
"label": "Manufactured Qty",
"no_copy": 1,
"oldfieldname": "produced_qty",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "project_name",
"fieldtype": "Link",
"in_filter": 1,
"label": "Project Name",
"oldfieldname": "project_name",
"oldfieldtype": "Link",
"options": "Project",
"permlevel": 0,
"depends_on": "sales_order",
"fieldname": "expected_delivery_date",
"fieldtype": "Date",
"label": "Expected Delivery Date",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "warehouses",
"fieldtype": "Section Break",
"label": "Warehouses",
"options": "icon-building",
"permlevel": 0
},
{
"depends_on": "production_item",
"description": "Manufactured quantity will be updated in this warehouse",
"fieldname": "fg_warehouse",
"fieldtype": "Link",
"in_list_view": 0,
"label": "For Warehouse",
"options": "Warehouse",
"permlevel": 0,
"read_only": 0,
"reqd": 0
},
{
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"label": "Work-in-Progress Warehouse",
"options": "Warehouse",
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Info",
"options": "icon-file-text",
"permlevel": 0,
"read_only": 0
},
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
"permlevel": 0,
"read_only": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Item Description",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "project_name",
"fieldtype": "Link",
"in_filter": 1,
"label": "Project Name",
"oldfieldname": "project_name",
"oldfieldtype": "Link",
"options": "Project",
"permlevel": 0,
"read_only": 0
},
{
"fieldname": "column_break2",
"fieldtype": "Column Break",
"permlevel": 0,
"read_only": 0,
"width": "50%"
},
},
{
"depends_on": "production_item",
"fieldname": "stock_uom",
"fieldtype": "Link",
"label": "Stock UOM",
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"options": "UOM",
"permlevel": 0,
"depends_on": "production_item",
"fieldname": "stock_uom",
"fieldtype": "Link",
"label": "Stock UOM",
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"options": "UOM",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"read_only": 0,
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"read_only": 0,
"reqd": 1
},
},
{
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Amended From",
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Production Order",
"permlevel": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
"label": "Amended From",
"no_copy": 1,
"oldfieldname": "amended_from",
"oldfieldtype": "Data",
"options": "Production Order",
"permlevel": 0,
"read_only": 1
}
],
"icon": "icon-cogs",
"idx": 1,
"in_create": 0,
"is_submittable": 1,
"modified": "2014-06-23 07:55:50.092300",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order",
"owner": "Administrator",
],
"icon": "icon-cogs",
"idx": 1,
"in_create": 0,
"is_submittable": 1,
"modified": "2014-09-15 11:45:48.591196",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order",
"owner": "Administrator",
"permissions": [
{
"amend": 1,
"apply_user_permissions": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"submit": 1,
"amend": 1,
"apply_user_permissions": 1,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"submit": 1,
"write": 1
},
},
{
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"apply_user_permissions": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "Material User"
}
]
}
}

View File

@ -24,6 +24,7 @@ class ProductionOrder(Document):
self.validate_bom_no()
self.validate_sales_order()
self.validate_warehouse()
self.set_fixed_cost()
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
@ -55,6 +56,10 @@ class ProductionOrder(Document):
for w in [self.fg_warehouse, self.wip_warehouse]:
validate_warehouse_company(w, self.company)
def set_fixed_cost(self):
if self.total_fixed_cost==None:
self.total_fixed_cost = frappe.db.get_value("BOM", self.bom_no, "total_fixed_cost")
def validate_production_order_against_so(self):
# already ordered qty
ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order`
@ -156,11 +161,10 @@ def get_item_details(item):
return {}
res = res[0]
bom = frappe.db.sql("""select name from `tabBOM` where item=%s
and ifnull(is_default, 0)=1""", item)
bom = frappe.db.sql("""select name as bom_no,total_fixed_cost from `tabBOM` where item=%s
and ifnull(is_default, 0)=1""", item, as_dict=1)
if bom:
res.bom_no = bom[0][0]
res.update(bom[0])
return res
@frappe.whitelist()

View File

@ -54,5 +54,4 @@ class TestProductionOrder(unittest.TestCase):
self.assertRaises(StockOverProductionError, s.submit)
test_records = frappe.get_test_records('Production Order')
test_records = frappe.get_test_records('Production Order')

View File

@ -153,7 +153,6 @@ class ProductionPlanningTool(Document):
pi.so_pending_qty = flt(p['pending_qty'])
pi.planned_qty = flt(p['pending_qty'])
def validate_data(self):
self.validate_company()
for d in self.get('pp_details'):

View File

@ -0,0 +1,10 @@
[
{
"doctype": "Workstation",
"name": "_Test Workstation 1",
"workstation_name": "_Test Workstation 1",
"warehouse": "_Test warehouse - _TC",
"fixed_cycle_cost": 1000,
"hour_rate":100
}
]

View File

@ -0,0 +1,12 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_dependencies = ["Warehouse"]
test_records = frappe.get_test_records('Workstation')
class TestWorkstation(unittest.TestCase):
pass

View File

@ -1,155 +1,161 @@
{
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:workstation_name",
"creation": "2013-01-10 16:34:17",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:workstation_name",
"creation": "2013-01-10 16:34:17",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"fieldname": "workstation_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Workstation Name",
"oldfieldname": "workstation_name",
"oldfieldtype": "Data",
"permlevel": 0,
"fieldname": "workstation_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Workstation Name",
"oldfieldname": "workstation_name",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"permlevel": 0,
"reqd": 1
},
},
{
"fieldname": "description",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Text",
"permlevel": 0,
"fieldname": "description",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Text",
"permlevel": 0,
"width": "300px"
},
},
{
"fieldname": "capacity",
"fieldtype": "Data",
"hidden": 1,
"in_list_view": 1,
"label": "Capacity",
"oldfieldname": "capacity",
"oldfieldtype": "Data",
"permlevel": 0,
"fieldname": "capacity",
"fieldtype": "Data",
"hidden": 1,
"in_list_view": 1,
"label": "Capacity",
"oldfieldname": "capacity",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 0
},
},
{
"fieldname": "capacity_units",
"fieldtype": "Select",
"hidden": 1,
"in_list_view": 1,
"label": "Capacity Units",
"oldfieldname": "capacity_units",
"oldfieldtype": "Select",
"options": "\nUnits/Shifts\nUnits/Hour",
"permlevel": 0,
"fieldname": "capacity_units",
"fieldtype": "Select",
"hidden": 1,
"in_list_view": 1,
"label": "Capacity Units",
"oldfieldname": "capacity_units",
"oldfieldtype": "Select",
"options": "\nUnits/Shifts\nUnits/Hour",
"permlevel": 0,
"reqd": 0
},
},
{
"fieldname": "hour_rate_labour",
"fieldtype": "Float",
"label": "Hour Rate Labour",
"oldfieldname": "hour_rate_labour",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "fixed_cycle_cost",
"fieldtype": "Float",
"label": "Fixed Cycle Cost",
"permlevel": 0
},
{
"fieldname": "hour_rate_labour",
"fieldtype": "Float",
"label": "Hour Rate Labour",
"oldfieldname": "hour_rate_labour",
"oldfieldtype": "Currency",
"permlevel": 0,
"reqd": 0
},
},
{
"fieldname": "over_heads",
"fieldtype": "Section Break",
"label": "Overheads",
"oldfieldtype": "Section Break",
"fieldname": "over_heads",
"fieldtype": "Section Break",
"label": "Overheads",
"oldfieldtype": "Section Break",
"permlevel": 0
},
},
{
"description": "Electricity cost per hour",
"fieldname": "hour_rate_electricity",
"fieldtype": "Float",
"label": "Electricity Cost",
"oldfieldname": "hour_rate_electricity",
"oldfieldtype": "Currency",
"description": "Electricity cost per hour",
"fieldname": "hour_rate_electricity",
"fieldtype": "Float",
"label": "Electricity Cost",
"oldfieldname": "hour_rate_electricity",
"oldfieldtype": "Currency",
"permlevel": 0
},
},
{
"description": "Consumable cost per hour",
"fieldname": "hour_rate_consumable",
"fieldtype": "Float",
"label": "Consumable Cost",
"oldfieldname": "hour_rate_consumable",
"oldfieldtype": "Currency",
"description": "Consumable cost per hour",
"fieldname": "hour_rate_consumable",
"fieldtype": "Float",
"label": "Consumable Cost",
"oldfieldname": "hour_rate_consumable",
"oldfieldtype": "Currency",
"permlevel": 0
},
},
{
"description": "Rent per hour",
"fieldname": "hour_rate_rent",
"fieldtype": "Float",
"label": "Rent Cost",
"oldfieldname": "hour_rate_rent",
"oldfieldtype": "Currency",
"description": "Rent per hour",
"fieldname": "hour_rate_rent",
"fieldtype": "Float",
"label": "Rent Cost",
"oldfieldname": "hour_rate_rent",
"oldfieldtype": "Currency",
"permlevel": 0
},
},
{
"fieldname": "overhead",
"fieldtype": "Float",
"label": "Overhead",
"oldfieldname": "overhead",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "overhead",
"fieldtype": "Float",
"label": "Overhead",
"oldfieldname": "overhead",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 1
},
},
{
"fieldname": "hour_rate_section_break",
"fieldtype": "Section Break",
"label": "Hour Rate",
"oldfieldtype": "Section Break",
"fieldname": "hour_rate_section_break",
"fieldtype": "Section Break",
"label": "Hour Rate",
"oldfieldtype": "Section Break",
"permlevel": 0
},
},
{
"fieldname": "hour_rate",
"fieldtype": "Float",
"label": "Hour Rate",
"oldfieldname": "hour_rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"fieldname": "hour_rate",
"fieldtype": "Float",
"label": "Hour Rate",
"oldfieldname": "hour_rate",
"oldfieldtype": "Currency",
"permlevel": 0,
"read_only": 1
}
],
"icon": "icon-wrench",
"idx": 1,
"modified": "2014-05-27 03:49:22.635046",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Workstation",
"owner": "Administrator",
],
"icon": "icon-wrench",
"idx": 1,
"modified": "2014-09-15 10:59:07.960814",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Workstation",
"owner": "Administrator",
"permissions": [
{
"apply_user_permissions": 1,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"submit": 0,
"apply_user_permissions": 1,
"create": 1,
"delete": 1,
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Manufacturing User",
"submit": 0,
"write": 1
}
]
}
}

View File

@ -80,3 +80,4 @@ execute:frappe.delete_doc("DocType", "Landed Cost Wizard")
erpnext.patches.v4_2.default_website_style
erpnext.patches.v4_2.set_company_country
erpnext.patches.v4_2.update_sales_order_invoice_field_name
erpnext.patches.v4_2.cost_of_production_cycle

View File

@ -0,0 +1,9 @@
# 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():
frappe.reload_doc("manufacturing", "doctype", "bom")
frappe.db.sql("""update tabBOM set total_variable_cost = total_cost""")

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
def execute(filters=None):
@ -12,9 +13,9 @@ def execute(filters=None):
filters["from_time"] = "00:00:00"
filters["to_time"] = "24:00:00"
columns = ["Time Log:Link/Time Log:120", "Employee::150", "From Datetime::140",
"To Datetime::140", "Hours::70", "Activity Type::120", "Task:Link/Task:150",
"Task Subject::180", "Project:Link/Project:120", "Status::70"]
columns = [_("Time Log") + ":Link/Time Log:120", _("Employee") + "::150", _("From Datetime") + "::140",
_("To Datetime") + "::140", _("Hours") + "::70", _("Activity Type") + "::120", _("Task") + ":Link/Task:150",
_("Task Subject") + "::180", _("Project") + ":Link/Project:120", _("Status") + "::70"]
user_map = get_user_map()
task_map = get_task_map()

View File

@ -1,7 +1,8 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
import frappe
from frappe import _
def execute(filters=None):
columns = get_columns()
@ -21,11 +22,11 @@ def execute(filters=None):
return columns, data
def get_columns():
return ["Project Id:Link/Project:140", "Cost of Purchased Items:Currency:160",
"Cost of Issued Items:Currency:160", "Cost of Delivered Items:Currency:160",
"Project Name::120", "Project Status::120", "Company:Link/Company:100",
"Customer:Link/Customer:140", "Project Value:Currency:120",
"Project Start Date:Date:120", "Completion Date:Date:120"]
return [_("Project Id") + ":Link/Project:140", _("Cost of Purchased Items") + ":Currency:160",
_("Cost of Issued Items") + ":Currency:160", _("Cost of Delivered Items") + ":Currency:160",
_("Project Name") + "::120", _("Project Status") + "::120", _("Company") + ":Link/Company:100",
_("Customer") + ":Link/Customer:140", _("Project Value") + ":Currency:120",
_("Project Start Date") + ":Date:120", _("Completion Date") + ":Date:120"]
def get_project_details():
return frappe.db.sql(""" select name, project_name, status, company, customer, project_value,

View File

@ -7,21 +7,36 @@ var get_filters = function(){
"fieldname":"period",
"label": __("Period"),
"fieldtype": "Select",
"options": ["Monthly", "Quarterly", "Half-Yearly", "Yearly"].join("\n"),
"options": [
{ "value": "Monthly", "label": __("Monthly") },
{ "value": "Quarterly", "label": __("Quarterly") },
{ "value": "Half-Yearly", "label": __("Half-Yearly") },
{ "value": "Yearly", "label": __("Yearly") }
],
"default": "Monthly"
},
{
"fieldname":"based_on",
"label": __("Based On"),
"fieldtype": "Select",
"options": ["Item", "Item Group", "Supplier", "Supplier Type", "Project"].join("\n"),
"options": [
{ "value": "Item", "label": __("Item") },
{ "value": "Item Group", "label": __("Item Group") },
{ "value": "Supplier", "label": __("Supplier") },
{ "value": "Supplier Type", "label": __("Supplier Type") },
{ "value": "Supplier Type", "label": __("Project") }
],
"default": "Item"
},
{
"fieldname":"group_by",
"label": __("Group By"),
"fieldtype": "Select",
"options": ["", "Item", "Supplier"].join("\n"),
"options": [
"",
{ "value": "Item", "label": __("Item") },
{ "value": "Supplier", "label": __("Supplier") }
],
"default": ""
},
{

View File

@ -7,21 +7,37 @@ var get_filters = function(){
"fieldname":"period",
"label": __("Period"),
"fieldtype": "Select",
"options": ["Monthly", "Quarterly", "Half-Yearly", "Yearly"].join("\n"),
"options": [
{ "value": "Monthly", "label": __("Monthly") },
{ "value": "Quarterly", "label": __("Quarterly") },
{ "value": "Half-Yearly", "label": __("Half-Yearly") },
{ "value": "Yearly", "label": __("Yearly") }
],
"default": "Monthly"
},
{
"fieldname":"based_on",
"label": __("Based On"),
"fieldtype": "Select",
"options": ["Item", "Item Group", "Customer", "Customer Group", "Territory", "Project"].join("\n"),
"options": [
{ "value": "Item", "label": __("Item") },
{ "value": "Item Group", "label": __("Item Group") },
{ "value": "Customer", "label": __("Customer") },
{ "value": "Customer Group", "label": __("Customer Group") },
{ "value": "Territory", "label": __("Territory") },
{ "value": "Supplier Type", "label": __("Project") }
],
"default": "Item"
},
{
"fieldname":"group_by",
"label": __("Group By"),
"fieldtype": "Select",
"options": ["", "Item", "Customer"].join("\n"),
"options": [
"",
{ "value": "Item", "label": __("Item") },
{ "value": "Customer", "label": __("Customer") }
],
"default": ""
},
{

View File

@ -282,7 +282,7 @@
],
"icon": "icon-user",
"idx": 1,
"modified": "2014-08-07 06:57:25.248707",
"modified": "2014-09-10 16:41:07.553182",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer",
@ -309,6 +309,14 @@
"read": 1,
"role": "Sales User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager"
},
{
"amend": 0,
"create": 1,
@ -330,6 +338,38 @@
"read": 1,
"role": "Sales Master Manager",
"write": 1
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Material User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Material Manager"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User"
},
{
"email": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager"
}
],
"search_fields": "customer_name,customer_group,territory",

View File

@ -22,5 +22,13 @@
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
},
{
"company": "_Test Company",
"customer_group": "_Test Customer Group",
"customer_name": "_Test Customer 3",
"customer_type": "Individual",
"doctype": "Customer",
"territory": "_Test Territory"
}
]

View File

@ -1,5 +1,5 @@
{
"allow_import": 1,
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
@ -832,7 +832,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 1,
"modified": "2014-08-12 05:04:36.157045",
"modified": "2014-09-09 05:35:33.413559",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",

View File

@ -332,7 +332,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:31.198440",
"modified": "2014-09-09 05:35:36.871532",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",

File diff suppressed because it is too large Load Diff

View File

@ -326,6 +326,11 @@ def make_delivery_note(source_name, target_doc=None):
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
def postprocess(source, target):
set_missing_values(source, target)
#Get the advance paid Journal Vouchers in Sales Invoice Advance
target.get_advances()
def set_missing_values(source, target):
target.is_pos = 0
target.ignore_pricing_rule = 1
@ -361,7 +366,18 @@ def make_sales_invoice(source_name, target_doc=None):
"doctype": "Sales Team",
"add_if_empty": True
}
}, target_doc, set_missing_values)
}, target_doc, postprocess)
def set_advance_vouchers(source, target):
advance_voucher_list = []
advance_voucher = frappe.db.sql("""
select
t1.name as voucher_no, t1.posting_date, t1.remark, t2.account,
t2.name as voucher_detail_no, {amount_query} as payment_amount, t2.is_advance
from
`tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
""")
return doclist

View File

@ -1,5 +1,6 @@
[
{
"advance_paid": 0.0,
"company": "_Test Company",
"conversion_rate": 1.0,
"currency": "INR",

View File

@ -415,7 +415,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2014-09-08 08:06:31.435020",
"modified": "2014-09-09 05:35:37.173841",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",

View File

@ -8,7 +8,7 @@ pscript['onload_Sales Browser'] = function(wrapper){
wrapper.appframe.add_module_icon("Selling")
wrapper.appframe.set_title_right('Refresh', function() {
wrapper.appframe.set_title_right(__('Refresh'), function() {
wrapper.make_tree();
});
@ -44,7 +44,7 @@ pscript['onshow_Sales Browser'] = function(wrapper){
// set route
var ctype = frappe.get_route()[1] || 'Territory';
wrapper.appframe.set_title(ctype+' Tree')
wrapper.appframe.set_title(__('{0} Tree',[__(ctype)]));
if(erpnext.sales_chart && erpnext.sales_chart.ctype != ctype) {
wrapper.make_tree();
@ -64,7 +64,7 @@ erpnext.SalesChart = Class.extend({
this.tree = new frappe.ui.Tree({
parent: $(parent),
label: root,
label: __(root),
args: {ctype: ctype},
method: 'erpnext.selling.page.sales_browser.sales_browser.get_children',
toolbar: [
@ -112,20 +112,20 @@ erpnext.SalesChart = Class.extend({
var fields = [
{fieldtype:'Data', fieldname: 'name_field',
label:'New ' + me.ctype + ' Name', reqd:true},
{fieldtype:'Select', fieldname:'is_group', label:'Group Node', options:'No\nYes',
label:__('New {0} Name',[__(me.ctype)]), reqd:true},
{fieldtype:'Select', fieldname:'is_group', label:__('Group Node'), options:'No\nYes',
description: __("Further nodes can be only created under 'Group' type nodes")},
{fieldtype:'Button', fieldname:'create_new', label:'Create New' }
{fieldtype:'Button', fieldname:'create_new', label:__('Create New') }
]
if(me.ctype == "Sales Person") {
fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:'Employee',
fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:__('Employee'),
options:'Employee', description: __("Please enter Employee Id of this sales parson")});
}
// the dialog
var d = new frappe.ui.Dialog({
title: __('New ') + __(me.ctype),
title: __('New {0}',[__(me.ctype)]),
fields: fields
})

Some files were not shown because too many files have changed in this diff Show More