Compare commits
217 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50e363b24e | ||
|
|
bc176b6bf8 | ||
|
|
784b49e54e | ||
|
|
04fb6e1a45 | ||
|
|
dffd7c3889 | ||
|
|
0c7594e5ed | ||
|
|
5105f909d6 | ||
|
|
2ab9d6e92c | ||
|
|
7580723ab3 | ||
|
|
52fef71c14 | ||
|
|
2cd02af80a | ||
|
|
0b0ec3536c | ||
|
|
6b35ea873b | ||
|
|
ecf220a721 | ||
|
|
04fb1c7fe4 | ||
|
|
53bd62eafc | ||
|
|
ff68bf2609 | ||
|
|
fdd0db3459 | ||
|
|
f92465981c | ||
|
|
885c70984d | ||
|
|
9c15ef903d | ||
|
|
bc799885d0 | ||
|
|
cb129264cb | ||
|
|
fe9cd1d875 | ||
|
|
64fbe955c7 | ||
|
|
0988440fd9 | ||
|
|
274dd4ada0 | ||
|
|
724fd82419 | ||
|
|
3f2604eff6 | ||
|
|
c761fefb78 | ||
|
|
203cb10ef7 | ||
|
|
90c66b1998 | ||
|
|
fed431f908 | ||
|
|
bd9745ba72 | ||
|
|
8fb123b20e | ||
|
|
333ccd212b | ||
|
|
c8cc8b7115 | ||
|
|
ec44fa95ce | ||
|
|
a25e8ea0bc | ||
|
|
ea02b9a5c3 | ||
|
|
74a63bf003 | ||
|
|
a0f2510b01 | ||
|
|
0820161157 | ||
|
|
56bc215855 | ||
|
|
8687d25f7e | ||
|
|
9cea01fa8b | ||
|
|
e06d01e3ed | ||
|
|
11243a4fb4 | ||
|
|
b9e5cd0df4 | ||
|
|
a1f1edc786 | ||
|
|
e2d8dd0663 | ||
|
|
d1605c5cb2 | ||
|
|
64ca52fb77 | ||
|
|
2f11a3bdaf | ||
|
|
943dc1f59c | ||
|
|
6d1c994bc9 | ||
|
|
93cdee4503 | ||
|
|
dfac6848cc | ||
|
|
8ad0b4e0b9 | ||
|
|
b8cd92f1aa | ||
|
|
1fe48cb820 | ||
|
|
723b046c5b | ||
|
|
035160c9a6 | ||
|
|
01c7ce1da3 | ||
|
|
9cf2910ba1 | ||
|
|
c8da7b7d32 | ||
|
|
9679d31397 | ||
|
|
38bebe1b83 | ||
|
|
ffbc11e8de | ||
|
|
818d9674d9 | ||
|
|
086f8942eb | ||
|
|
c3b492b237 | ||
|
|
9d0dd5066a | ||
|
|
e7f479b26a | ||
|
|
7ee45b4af2 | ||
|
|
5cce1e0929 | ||
|
|
be496bc91c | ||
|
|
59f063e5c3 | ||
|
|
af5820874c | ||
|
|
495db99719 | ||
|
|
123beb5a07 | ||
|
|
7ed4e080a2 | ||
|
|
e91025c0aa | ||
|
|
1ac9f2f50d | ||
|
|
bd9aa13db3 | ||
|
|
ed9d5cfdaf | ||
|
|
bf4547ca5f | ||
|
|
b45a6bcb88 | ||
|
|
ac59c2b300 | ||
|
|
6a8d7a1b91 | ||
|
|
5d71a28e97 | ||
|
|
7d100a1ee7 | ||
|
|
81dca110eb | ||
|
|
9c852108d0 | ||
|
|
e3ac032696 | ||
|
|
64cacfb077 | ||
|
|
ae4cc078ea | ||
|
|
0ee543e932 | ||
|
|
a123638d37 | ||
|
|
58996985ed | ||
|
|
5d0ce7939f | ||
|
|
4abf552d7b | ||
|
|
7c5ba957ac | ||
|
|
77f04e293a | ||
|
|
d1d3237784 | ||
|
|
76f0d26f1e | ||
|
|
65922d3079 | ||
|
|
810041cbe3 | ||
|
|
b9626659ea | ||
|
|
e3d13bee36 | ||
|
|
13bd538aca | ||
|
|
d72a24965b | ||
|
|
dc633fe360 | ||
|
|
39046d663d | ||
|
|
6b01abe9ad | ||
|
|
63e4d31aa6 | ||
|
|
f2a0161709 | ||
|
|
3c1a4a0b9b | ||
|
|
82cc2921d1 | ||
|
|
87edd86854 | ||
|
|
e37dd77923 | ||
|
|
e4f689184f | ||
|
|
85f825e98c | ||
|
|
89592c5180 | ||
|
|
587bd144d5 | ||
|
|
1f048b2426 | ||
|
|
1792ff3be7 | ||
|
|
fc595064e0 | ||
|
|
804b4acb9b | ||
|
|
5c7557914b | ||
|
|
381a9377d9 | ||
|
|
9bdd1aa1ed | ||
|
|
d0df28bfa0 | ||
|
|
1966225450 | ||
|
|
4cee27eec0 | ||
|
|
c7d4eaee79 | ||
|
|
43c1a9b502 | ||
|
|
b937fac3ce | ||
|
|
53d94996ad | ||
|
|
26f6752c1e | ||
|
|
bb429745c0 | ||
|
|
909f0c38f1 | ||
|
|
a790ba05f4 | ||
|
|
11fc4f85d0 | ||
|
|
17452a1695 | ||
|
|
7c3d48e353 | ||
|
|
5d288e407c | ||
|
|
f64fae752f | ||
|
|
82763f052f | ||
|
|
bafc73568a | ||
|
|
d015195617 | ||
|
|
b2f550ccb3 | ||
|
|
41413af42d | ||
|
|
ec60ebde6f | ||
|
|
ce81a61fe7 | ||
|
|
dc76b3fa20 | ||
|
|
828cbee12a | ||
|
|
5f5ef16b91 | ||
|
|
686ef8308a | ||
|
|
b63ad44b10 | ||
|
|
5ef121bc10 | ||
|
|
42c1836db5 | ||
|
|
9dbdef3bd5 | ||
|
|
9fd42ed2f7 | ||
|
|
000835c454 | ||
|
|
de1f934e22 | ||
|
|
7cbd916b00 | ||
|
|
56fcf30cb9 | ||
|
|
ebbdd772a9 | ||
|
|
6268d83173 | ||
|
|
4599467939 | ||
|
|
d3613479c6 | ||
|
|
6bf301f53c | ||
|
|
27d7f21553 | ||
|
|
8f87cff4bd | ||
|
|
8f39766924 | ||
|
|
39669f2717 | ||
|
|
3c1017c43b | ||
|
|
0b18a2d347 | ||
|
|
6262496e70 | ||
|
|
c9963f1805 | ||
|
|
8a2b1bcb97 | ||
|
|
b8ecf7c757 | ||
|
|
cf89fa2253 | ||
|
|
419c1eb90d | ||
|
|
2c214e0362 | ||
|
|
7d04dd0bfd | ||
|
|
f1371a7ee7 | ||
|
|
995a78421a | ||
|
|
352187bee6 | ||
|
|
c6d8121f4a | ||
|
|
030ade428b | ||
|
|
c87595b2da | ||
|
|
42f2674cba | ||
|
|
5359f2651a | ||
|
|
42dcffdad4 | ||
|
|
f7c1743b28 | ||
|
|
64aa6620be | ||
|
|
ed43f8015c | ||
|
|
d3fe7ec858 | ||
|
|
c8b406d050 | ||
|
|
2aa577f110 | ||
|
|
f06d175061 | ||
|
|
74b2116adb | ||
|
|
2204d0af94 | ||
|
|
b8a568765d | ||
|
|
cf29f6468d | ||
|
|
aded46d33e | ||
|
|
b8dd046c84 | ||
|
|
e5fa5e6111 | ||
|
|
b89cf1b3ec | ||
|
|
a33d468d30 | ||
|
|
e481a211b1 | ||
|
|
ca23b5ecfd | ||
|
|
11190268ab | ||
|
|
a19150ddaf | ||
|
|
c17dff4b01 |
@@ -1,2 +1,2 @@
|
||||
from __future__ import unicode_literals
|
||||
__version__ = '5.0.14'
|
||||
__version__ = '5.1.0'
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -44,7 +44,7 @@
|
||||
"label": "Is Group",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
@@ -57,7 +57,7 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "root_type",
|
||||
@@ -147,7 +147,8 @@
|
||||
"label": "Lft",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rgt",
|
||||
@@ -156,7 +157,8 @@
|
||||
"label": "Rgt",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "old_parent",
|
||||
@@ -171,7 +173,7 @@
|
||||
"icon": "icon-money",
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"modified": "2015-05-28 14:10:40.606010",
|
||||
"modified": "2015-06-14 20:57:55.471334",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"country_code": "ni",
|
||||
"name": "Catalogo de Cuentas",
|
||||
"name": "Catalogo de Cuentas Nicaragua",
|
||||
"is_active": "Yes",
|
||||
"tree": {
|
||||
"Activo": {
|
||||
@@ -72,7 +72,7 @@
|
||||
"IVA Acreditable por Importaciones": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"IVA Acreditable por Prestacion de Servicios": {
|
||||
"IVA Acreditable por Prestacion de Servicios y Uso y Goce de Bienes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Acreditacion Proporcional": {}
|
||||
@@ -229,11 +229,19 @@
|
||||
"Impuesto al Valor Agregado por Pagar": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Impuesto sobre la Renta": {
|
||||
"Impuesto sobre la Renta por Actividades Economicas": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Impuestos Municipales": {
|
||||
"account_type": "Tax"
|
||||
"Impuesto Municipal Sobre Ingresos": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Recoleccion Basura": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Matricula Municipal": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Retenciones por Pagar": {
|
||||
@@ -241,7 +249,13 @@
|
||||
"Retencion Rentas del Trabajo Tarifa Progresiva": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva por Rentas del Trabajo": {
|
||||
"Retencion Definitiva 10% por Rentas del Trabajo - Indemnizacion Adicional": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 12.5% por Rentas del Trabajo - Dietas": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 15% por Rentas del Trabajo - No Residentes": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
},
|
||||
@@ -258,11 +272,26 @@
|
||||
"Retencion 5% compra Madera en Rollo": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 1.5% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 3% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 10% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 15% Actividades Economicas No Residentes": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Otras Retenciones 10%": {
|
||||
"account_type": "Tax"
|
||||
}
|
||||
},
|
||||
"Rentas y Ganancias de Capital": {
|
||||
"Retencion Defintiva 15% por Rentas de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Defintiva 10% por Rentas de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
@@ -272,10 +301,16 @@
|
||||
"Retencion Definitiva 10% por Ganancia de Capital": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva Actividades Economicas No Residentes": {
|
||||
"Retencion Definitiva 0.25% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva Transacciones Bursatiles": {
|
||||
"Retencion Definitiva 1% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 1.5% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retencion Definitiva 2% Transacciones Bursatiles": {
|
||||
"account_type": "Tax"
|
||||
},
|
||||
"Retenciones Defintiva 5% Fondos de Inversion": {
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "check_supplier_invoice_uniqueness",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Supplier Invoice Number Uniqueness",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "If enabled, the system will post accounting entries for inventory automatically.",
|
||||
@@ -43,7 +50,7 @@
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-05 05:11:34.163902",
|
||||
"modified": "2015-06-11 06:06:34.047890",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ui.form.on("Bank Reconciliation", {
|
||||
refresh: function(frm) {
|
||||
frm.disable_save();
|
||||
},
|
||||
|
||||
update_clearance_date: function(frm) {
|
||||
return frappe.call({
|
||||
method: "update_details",
|
||||
@@ -33,5 +37,4 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
|
||||
cur_frm.set_value("from_date", frappe.datetime.month_start());
|
||||
cur_frm.set_value("to_date", frappe.datetime.month_end());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,8 @@ class BankReconciliation(Document):
|
||||
where
|
||||
t2.parent = t1.name and t2.account = %s
|
||||
and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1
|
||||
and ifnull(t1.is_opening, 'No') = 'No' %s""" %
|
||||
and ifnull(t1.is_opening, 'No') = 'No' %s
|
||||
order by t1.posting_date""" %
|
||||
('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
|
||||
|
||||
self.set('journal_entries', [])
|
||||
|
||||
@@ -54,7 +54,7 @@ class CForm(Document):
|
||||
frappe.throw(_("Please enter atleast 1 invoice in the table"))
|
||||
|
||||
def set_total_invoiced_amount(self):
|
||||
total = sum([flt(d.base_grand_total) for d in self.get('invoices')])
|
||||
total = sum([flt(d.grand_total) for d in self.get('invoices')])
|
||||
frappe.db.set(self, 'total_invoiced_amount', total)
|
||||
|
||||
def get_invoice_details(self, invoice_no):
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Party",
|
||||
"options": "party_type",
|
||||
"permlevel": 0
|
||||
"permlevel": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cost_center",
|
||||
@@ -192,7 +193,7 @@
|
||||
"icon": "icon-list",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2015-04-27 20:32:48.246818",
|
||||
"modified": "2015-06-14 20:57:19.800276",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "GL Entry",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate
|
||||
from frappe.utils import flt, fmt_money, getdate, formatdate, cstr
|
||||
from frappe import _
|
||||
|
||||
from frappe.model.document import Document
|
||||
@@ -118,7 +118,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry`
|
||||
where against_voucher_type=%s and against_voucher=%s
|
||||
and account = %s and party_type=%s and party=%s""",
|
||||
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s""",
|
||||
(against_voucher_type, against_voucher, account, party_type, party))[0][0] or 0.0)
|
||||
|
||||
if against_voucher_type == 'Purchase Invoice':
|
||||
@@ -127,8 +127,9 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga
|
||||
against_voucher_amount = flt(frappe.db.sql("""
|
||||
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
|
||||
from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
|
||||
and account = %s and party_type=%s and party=%s and ifnull(against_voucher, '') = ''""",
|
||||
(against_voucher, account, party_type, party))[0][0])
|
||||
and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s
|
||||
and ifnull(against_voucher, '') = ''""",
|
||||
(against_voucher, account, cstr(party_type), cstr(party)))[0][0])
|
||||
|
||||
if not against_voucher_amount:
|
||||
frappe.throw(_("Against Journal Entry {0} is already adjusted against some other voucher")
|
||||
@@ -157,3 +158,22 @@ def validate_frozen_account(account, adv_adj=None):
|
||||
frappe.throw(_("Account {0} is frozen").format(account))
|
||||
elif frozen_accounts_modifier not in frappe.get_roles():
|
||||
frappe.throw(_("Not authorized to edit frozen Account {0}").format(account))
|
||||
|
||||
def update_against_account(voucher_type, voucher_no):
|
||||
entries = frappe.db.get_all("GL Entry",
|
||||
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
|
||||
fields=["name", "party", "against", "debit", "credit", "account"])
|
||||
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in entries:
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in entries:
|
||||
if flt(d.debit > 0):
|
||||
new_against = ", ".join(list(set(accounts_credited)))
|
||||
if flt(d.credit > 0):
|
||||
new_against = ", ".join(list(set(accounts_debited)))
|
||||
|
||||
if d.against != new_against:
|
||||
frappe.db.set_value("GL Entry", d.name, "against", new_against)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Posting Date",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "posting_date",
|
||||
@@ -445,7 +445,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-04-27 20:32:31.655580",
|
||||
"modified": "2015-06-29 15:28:12.529019",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, cint
|
||||
from frappe.utils import cstr, flt, fmt_money, formatdate, getdate
|
||||
from frappe import msgprint, _, scrub
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
from erpnext.controllers.accounts_controller import AccountsController
|
||||
@@ -81,7 +81,7 @@ class JournalEntry(AccountsController):
|
||||
frappe.throw(_("Row {0}: Party Type and Party is only applicable against Receivable / Payable account").format(d.idx))
|
||||
|
||||
def check_credit_limit(self):
|
||||
customers = list(set([d.party for d in self.get("accounts")
|
||||
customers = list(set([d.party for d in self.get("accounts")
|
||||
if d.party_type=="Customer" and d.party and flt(d.debit) > 0]))
|
||||
if customers:
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
@@ -243,8 +243,8 @@ class JournalEntry(AccountsController):
|
||||
def set_against_account(self):
|
||||
accounts_debited, accounts_credited = [], []
|
||||
for d in self.get("accounts"):
|
||||
if flt(d.debit > 0): accounts_debited.append(d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.account)
|
||||
if flt(d.debit > 0): accounts_debited.append(d.party or d.account)
|
||||
if flt(d.credit) > 0: accounts_credited.append(d.party or d.account)
|
||||
|
||||
for d in self.get("accounts"):
|
||||
if flt(d.debit > 0): d.against_account = ", ".join(list(set(accounts_credited)))
|
||||
@@ -275,29 +275,27 @@ class JournalEntry(AccountsController):
|
||||
else:
|
||||
msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
|
||||
|
||||
company_currency = get_company_currency(self.company)
|
||||
|
||||
for d in self.get('accounts'):
|
||||
if d.against_invoice and d.credit:
|
||||
currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
|
||||
|
||||
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
|
||||
r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = company_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), \
|
||||
r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
|
||||
d.against_sales_order))
|
||||
|
||||
if d.against_voucher and d.debit:
|
||||
bill_no = frappe.db.sql("""select bill_no, bill_date, currency
|
||||
bill_no = frappe.db.sql("""select bill_no, bill_date
|
||||
from `tabPurchase Invoice` where name=%s""", d.against_voucher)
|
||||
if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
|
||||
not in ['na', 'not applicable', 'none']:
|
||||
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=bill_no[0][2]), bill_no[0][0],
|
||||
r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=company_currency), 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), \
|
||||
r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
|
||||
d.against_purchase_order))
|
||||
|
||||
if self.user_remark:
|
||||
@@ -428,12 +426,11 @@ class JournalEntry(AccountsController):
|
||||
def validate_expense_claim(self):
|
||||
for d in self.accounts:
|
||||
if d.against_expense_claim:
|
||||
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim", d.against_expense_claim,
|
||||
("total_sanctioned_amount", "total_amount_reimbursed"))
|
||||
pending_amount = cint(sanctioned_amount) - cint(reimbursed_amount)
|
||||
sanctioned_amount, reimbursed_amount = frappe.db.get_value("Expense Claim",
|
||||
d.against_expense_claim, ("total_sanctioned_amount", "total_amount_reimbursed"))
|
||||
pending_amount = flt(sanctioned_amount) - flt(reimbursed_amount)
|
||||
if d.debit > pending_amount:
|
||||
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. \
|
||||
Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
|
||||
frappe.throw(_("Row No {0}: Amount cannot be greater than Pending Amount against Expense Claim {1}. Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
|
||||
|
||||
def validate_credit_debit_note(self):
|
||||
if self.stock_entry:
|
||||
@@ -459,11 +456,11 @@ def get_default_bank_cash_account(company, voucher_type, mode_of_payment=None):
|
||||
if voucher_type=="Bank Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_bank_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Bank", "is_group": 0})
|
||||
elif voucher_type=="Cash Entry":
|
||||
account = frappe.db.get_value("Company", company, "default_cash_account")
|
||||
if not account:
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash"})
|
||||
account = frappe.db.get_value("Account", {"company": company, "account_type": "Cash", "is_group": 0})
|
||||
|
||||
if account:
|
||||
return {
|
||||
@@ -539,15 +536,13 @@ def get_opening_accounts(company):
|
||||
|
||||
|
||||
def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
|
||||
if not filters.get("party"):
|
||||
return []
|
||||
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark
|
||||
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s
|
||||
where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
|
||||
and (ifnull(jv_detail.against_invoice, '') = '' and ifnull(jv_detail.against_voucher, '') = ''
|
||||
and ifnull(jv_detail.against_jv, '') = '' )
|
||||
and jv.docstatus = 1 and jv.{0} like %s order by jv.name desc limit %s, %s""".format(searchfield),
|
||||
(filters["account"], filters["party"], "%{0}%".format(txt), start, page_len))
|
||||
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_outstanding(args):
|
||||
|
||||
@@ -44,6 +44,10 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.frm.disable_save();
|
||||
},
|
||||
|
||||
party: function() {
|
||||
var me = this
|
||||
|
||||
@@ -32,6 +32,7 @@ frappe.ui.form.on("Payment Tool", "onload", function(frm) {
|
||||
});
|
||||
|
||||
frappe.ui.form.on("Payment Tool", "refresh", function(frm) {
|
||||
frm.disable_save();
|
||||
frappe.ui.form.trigger("Payment Tool", "party_type");
|
||||
});
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"modified": "2015-02-21 03:59:08.154966",
|
||||
"modified": "2015-06-05 11:17:33.843334",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Tool",
|
||||
|
||||
@@ -224,3 +224,4 @@ cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
|
||||
else
|
||||
cur_frm.pformat.print_heading = __("Purchase Invoice");
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import cint, formatdate, flt
|
||||
from frappe.utils import cint, formatdate, flt, getdate
|
||||
from frappe import msgprint, _, throw
|
||||
from erpnext.setup.utils import get_company_currency
|
||||
import frappe.defaults
|
||||
@@ -39,6 +39,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.po_required()
|
||||
self.pr_required()
|
||||
self.validate_supplier_invoice()
|
||||
self.check_active_purchase_items()
|
||||
self.check_conversion_rate()
|
||||
self.validate_credit_to_acc()
|
||||
@@ -87,9 +88,7 @@ class PurchaseInvoice(BuyingController):
|
||||
throw(_("Conversion rate cannot be 0 or 1"))
|
||||
|
||||
def validate_credit_to_acc(self):
|
||||
root_type, account_type = frappe.db.get_value("Account", self.credit_to, ["root_type", "account_type"])
|
||||
if root_type != "Liability":
|
||||
frappe.throw(_("Credit To account must be a liability account"))
|
||||
account_type = frappe.db.get_value("Account", self.credit_to, "account_type")
|
||||
if account_type != "Payable":
|
||||
frappe.throw(_("Credit To account must be a Payable account"))
|
||||
|
||||
@@ -165,7 +164,7 @@ class PurchaseInvoice(BuyingController):
|
||||
elif item.expense_account not in against_accounts:
|
||||
# if no auto_accounting_for_stock or not a stock item
|
||||
against_accounts.append(item.expense_account)
|
||||
|
||||
|
||||
self.against_expense_account = ",".join(against_accounts)
|
||||
|
||||
def po_required(self):
|
||||
@@ -272,7 +271,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": tax.add_deduct_tax == "Add" and tax.base_tax_amount_after_discount_amount or 0,
|
||||
"credit": tax.add_deduct_tax == "Deduct" and tax.base_tax_amount_after_discount_amount or 0,
|
||||
"remarks": self.remarks,
|
||||
@@ -296,7 +295,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": item.expense_account,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": item.base_net_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": item.cost_center
|
||||
@@ -316,7 +315,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": stock_received_but_not_billed,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"debit": flt(item.item_tax_amount, self.precision("item_tax_amount", item)),
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
@@ -342,7 +341,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.get_gl_dict({
|
||||
"account": expenses_included_in_valuation,
|
||||
"cost_center": cost_center,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"credit": applicable_amount,
|
||||
"remarks": self.remarks or "Accounting Entry for Stock"
|
||||
})
|
||||
@@ -356,7 +355,7 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.write_off_account,
|
||||
"against": self.credit_to,
|
||||
"against": self.supplier,
|
||||
"credit": flt(self.write_off_amount),
|
||||
"remarks": self.remarks,
|
||||
"cost_center": self.write_off_cost_center
|
||||
@@ -375,7 +374,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
self.make_gl_entries_on_cancel()
|
||||
self.update_project()
|
||||
|
||||
|
||||
def update_project(self):
|
||||
project_list = []
|
||||
for d in self.items:
|
||||
@@ -386,6 +385,16 @@ class PurchaseInvoice(BuyingController):
|
||||
project.save()
|
||||
project_list.append(d.project_name)
|
||||
|
||||
def validate_supplier_invoice(self):
|
||||
if self.bill_date:
|
||||
if getdate(self.bill_date) > getdate(self.posting_date):
|
||||
frappe.throw("Supplier Invoice Date cannot be greater than Posting Date")
|
||||
if self.bill_no:
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
|
||||
pi = frappe.db.exists("Purchase Invoice", {"bill_no": self.bill_no, "fiscal_year": self.fiscal_year})
|
||||
if pi:
|
||||
frappe.throw("Supplier Invoice No exists in Purchase Invoice {0}".format(pi))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
from erpnext.controllers.queries import get_match_cond
|
||||
@@ -401,4 +410,4 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabAccount.company = '%(company)s'
|
||||
and tabAccount.%(key)s LIKE '%(txt)s'
|
||||
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
|
||||
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
@@ -49,6 +49,23 @@
|
||||
"read_only": 0,
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 1,
|
||||
"label": "Image",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "image_view",
|
||||
"fieldtype": "Image",
|
||||
"label": "Image View",
|
||||
"options": "image",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "quantity_and_rate",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -452,7 +469,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:16.341373",
|
||||
"modified": "2015-07-02 03:00:44.496683",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
||||
@@ -7,6 +7,7 @@ import frappe
|
||||
@frappe.whitelist()
|
||||
def get_items(price_list, sales_or_purchase, item=None):
|
||||
condition = ""
|
||||
order_by = ""
|
||||
args = {"price_list": price_list}
|
||||
|
||||
if sales_or_purchase == "Sales":
|
||||
@@ -30,16 +31,25 @@ def get_items(price_list, sales_or_purchase, item=None):
|
||||
item_code[0]["barcode"] = item
|
||||
return item_code
|
||||
|
||||
condition += " and (CONCAT(i.name, i.item_name) like %(name)s or (i.variant_of like %(name)s))"
|
||||
args["name"] = "%%%s%%" % item
|
||||
condition += " and ((CONCAT(i.name, i.item_name) like %(name)s) or (i.variant_of like %(name)s) or (i.item_group like %(name)s))"
|
||||
order_by = """if(locate(%(_name)s, i.name), locate(%(_name)s, i.name), 99999),
|
||||
if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
|
||||
if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
|
||||
if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
|
||||
args["name"] = "%%%s%%" % frappe.db.escape(item)
|
||||
args["_name"] = item.replace("%", "")
|
||||
|
||||
# locate function is used to sort by closest match from the beginning of the value
|
||||
return frappe.db.sql("""select i.name, i.item_name, i.image,
|
||||
item_det.price_list_rate, item_det.currency
|
||||
from `tabItem` i LEFT JOIN
|
||||
(select item_code, price_list_rate, currency from
|
||||
`tabItem Price` where price_list=%s) item_det
|
||||
`tabItem Price` where price_list=%(price_list)s) item_det
|
||||
ON
|
||||
(item_det.item_code=i.name or item_det.item_code=i.variant_of)
|
||||
where
|
||||
ifnull(i.has_variants, 0) = 0 and
|
||||
%s""" % ('%(price_list)s', condition), args, as_dict=1)
|
||||
{condition}
|
||||
order by
|
||||
{order_by}
|
||||
i.name""".format(condition=condition, order_by=order_by), args, as_dict=1)
|
||||
|
||||
@@ -392,8 +392,6 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
cur_frm.set_query("debit_to", function(doc) {
|
||||
return{
|
||||
filters: [
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
"options": "Customer",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "customer",
|
||||
@@ -502,7 +503,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -880,7 +881,7 @@
|
||||
"options": "Project",
|
||||
"permlevel": 0,
|
||||
"read_only": 0,
|
||||
"search_index": 1
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.source == 'Campaign'",
|
||||
@@ -1226,6 +1227,15 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"fieldname": "recurring_print_format",
|
||||
"fieldtype": "Link",
|
||||
"label": "Recurring Print Format",
|
||||
"options": "Print Format",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "against_income_account",
|
||||
"fieldtype": "Small Text",
|
||||
@@ -1243,7 +1253,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-05-27 02:48:02.897865",
|
||||
"modified": "2015-06-22 06:39:22.072544",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -65,8 +65,7 @@ class SalesInvoice(SellingController):
|
||||
self.set_against_income_account()
|
||||
self.validate_c_form()
|
||||
self.validate_time_logs_are_submitted()
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
|
||||
"items")
|
||||
self.validate_multiple_billing("Delivery Note", "dn_detail", "amount", "items")
|
||||
|
||||
def on_submit(self):
|
||||
super(SalesInvoice, self).on_submit()
|
||||
@@ -236,9 +235,7 @@ class SalesInvoice(SellingController):
|
||||
reconcile_against_document(lst)
|
||||
|
||||
def validate_debit_to_acc(self):
|
||||
root_type, account_type = frappe.db.get_value("Account", self.debit_to, ["root_type", "account_type"])
|
||||
if root_type != "Asset":
|
||||
frappe.throw(_("Debit To account must be a liability account"))
|
||||
account_type = frappe.db.get_value("Account", self.debit_to, "account_type")
|
||||
if account_type != "Receivable":
|
||||
frappe.throw(_("Debit To account must be a Receivable account"))
|
||||
|
||||
@@ -506,7 +503,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": tax.account_head,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"credit": flt(tax.base_tax_amount_after_discount_amount),
|
||||
"remarks": self.remarks,
|
||||
"cost_center": tax.cost_center
|
||||
@@ -520,7 +517,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": item.income_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"credit": item.base_net_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": item.cost_center
|
||||
@@ -551,7 +548,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.cash_bank_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"debit": self.paid_amount,
|
||||
"remarks": self.remarks,
|
||||
})
|
||||
@@ -575,7 +572,7 @@ class SalesInvoice(SellingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict({
|
||||
"account": self.write_off_account,
|
||||
"against": self.debit_to,
|
||||
"against": self.customer,
|
||||
"debit": self.write_off_amount,
|
||||
"remarks": self.remarks,
|
||||
"cost_center": self.write_off_cost_center
|
||||
@@ -590,7 +587,7 @@ def get_list_context(context=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_bank_cash_account(mode_of_payment, company):
|
||||
account = frappe.db.get_value("Mode of Payment Account",
|
||||
account = frappe.db.get_value("Mode of Payment Account",
|
||||
{"parent": mode_of_payment, "company": company}, "default_account")
|
||||
if not account:
|
||||
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
|
||||
@@ -614,7 +611,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabAccount.company = '%(company)s'
|
||||
and tabAccount.%(key)s LIKE '%(txt)s'
|
||||
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
|
||||
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_delivery_note(source_name, target_doc=None):
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
@@ -68,6 +68,23 @@
|
||||
"reqd": 1,
|
||||
"width": "200px"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 1,
|
||||
"label": "Image",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "image_view",
|
||||
"fieldtype": "Image",
|
||||
"label": "Image View",
|
||||
"options": "image",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "quantity_and_rate",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -505,7 +522,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:15.645114",
|
||||
"modified": "2015-07-02 02:59:08.413213",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, cstr
|
||||
from frappe.utils import flt, cstr, cint
|
||||
from frappe import _
|
||||
from frappe.model.meta import get_field_precision
|
||||
from erpnext.accounts.utils import validate_expense_against_budget
|
||||
@@ -56,12 +56,13 @@ def merge_similar_entries(gl_map):
|
||||
|
||||
def check_if_in_list(gle, gl_map):
|
||||
for e in gl_map:
|
||||
if e.account == gle.account and \
|
||||
cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||
and cstr(e.get('against_voucher_type')) == \
|
||||
cstr(gle.get('against_voucher_type')) \
|
||||
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
|
||||
return e
|
||||
if e.account == gle.account \
|
||||
and cstr(e.get('party_type'))==cstr(gle.get('party_type')) \
|
||||
and cstr(e.get('party'))==cstr(gle.get('party')) \
|
||||
and cstr(e.get('against_voucher'))==cstr(gle.get('against_voucher')) \
|
||||
and cstr(e.get('against_voucher_type')) == cstr(gle.get('against_voucher_type')) \
|
||||
and cstr(e.get('cost_center')) == cstr(gle.get('cost_center')):
|
||||
return e
|
||||
|
||||
def save_entries(gl_map, adv_adj, update_outstanding):
|
||||
validate_account_for_auto_accounting_for_stock(gl_map)
|
||||
@@ -81,14 +82,15 @@ def make_entry(args, adv_adj, update_outstanding):
|
||||
gle.submit()
|
||||
|
||||
def validate_account_for_auto_accounting_for_stock(gl_map):
|
||||
if gl_map[0].voucher_type=="Journal Entry":
|
||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
|
||||
if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
|
||||
and gl_map[0].voucher_type=="Journal Entry":
|
||||
aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
|
||||
where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
|
||||
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(entry.account), StockAccountInvalidTransaction)
|
||||
for entry in gl_map:
|
||||
if entry.account in aii_accounts:
|
||||
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
|
||||
.format(entry.account), StockAccountInvalidTransaction)
|
||||
|
||||
def round_off_debit_credit(gl_map):
|
||||
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
|
||||
@@ -101,7 +103,7 @@ def round_off_debit_credit(gl_map):
|
||||
debit_credit_diff += entry.debit - entry.credit
|
||||
|
||||
debit_credit_diff = flt(debit_credit_diff, precision)
|
||||
if abs(debit_credit_diff) >= (2.0 / (10**precision)):
|
||||
if abs(debit_credit_diff) >= (5.0 / (10**precision)):
|
||||
frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
|
||||
.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<button class="btn btn-primary btn-lg">{%= __("Start") %}</button>
|
||||
</p>
|
||||
<p class="pos-setting-message hide">
|
||||
<a class="btn btn-default btn-sm" href="#Form/POS Setting/New POS Setting">
|
||||
{%= __("Make new POS Setting") %}</a>
|
||||
<a class="btn btn-default btn-sm" href="#Form/POS Profile/New POS Profile">
|
||||
{%= __("Make new POS Profile") %}</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -16,12 +16,16 @@ def get_party_details(party=None, account=None, party_type="Customer", company=N
|
||||
|
||||
if not party:
|
||||
return {}
|
||||
|
||||
if not frappe.db.exists(party_type, party):
|
||||
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
|
||||
|
||||
return _get_party_details(party, account, party_type,
|
||||
company, posting_date, price_list, currency, doctype)
|
||||
|
||||
def _get_party_details(party=None, account=None, party_type="Customer", company=None,
|
||||
posting_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False):
|
||||
|
||||
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, doctype))
|
||||
|
||||
party = out[party_type.lower()]
|
||||
|
||||
@@ -51,7 +51,7 @@ class ReceivablePayableReport(object):
|
||||
currency_precision = get_currency_precision() or 2
|
||||
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
|
||||
|
||||
voucher_details = self.get_voucher_details()
|
||||
voucher_details = self.get_voucher_details(args.get("party_type"))
|
||||
|
||||
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
|
||||
|
||||
@@ -153,23 +153,26 @@ class ReceivablePayableReport(object):
|
||||
|
||||
return self.party_map
|
||||
|
||||
def get_voucher_details(self):
|
||||
def get_voucher_details(self, party_type):
|
||||
voucher_details = frappe._dict()
|
||||
|
||||
if party_type == "Customer":
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for si in frappe.db.sql("""select name, due_date
|
||||
from `tabSales Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(si.name, si)
|
||||
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
if party_type == "Supplier":
|
||||
for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
|
||||
from `tabPurchase Invoice` where docstatus=1""", as_dict=1):
|
||||
voucher_details.setdefault(pi.name, pi)
|
||||
|
||||
return voucher_details
|
||||
|
||||
def get_gl_entries(self, party_type):
|
||||
if not hasattr(self, "gl_entries"):
|
||||
conditions, values = self.prepare_conditions(party_type)
|
||||
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, debit, credit,
|
||||
voucher_type, voucher_no, against_voucher_type, against_voucher from `tabGL Entry`
|
||||
where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
|
||||
.format(conditions), values, as_dict=True)
|
||||
|
||||
@@ -187,7 +190,7 @@ class ReceivablePayableReport(object):
|
||||
|
||||
if self.filters.get(party_type_field):
|
||||
conditions.append("party=%s")
|
||||
values.append(self.filters.get(party_type_field))
|
||||
values.append(self.filters.get(party_type_field))
|
||||
|
||||
return " and ".join(conditions), values
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
|
||||
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
|
||||
|
||||
calculate_values(accounts, gl_entries_by_account, period_list)
|
||||
calculate_values(accounts_by_name, gl_entries_by_account, period_list)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name, period_list)
|
||||
out = prepare_data(accounts, balance_must_be, period_list)
|
||||
|
||||
@@ -92,16 +92,14 @@ def get_data(company, root_type, balance_must_be, period_list, ignore_closing_en
|
||||
|
||||
return out
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, period_list):
|
||||
for d in accounts:
|
||||
for name in ([d.name] + (d.collapsed_children or [])):
|
||||
for entry in gl_entries_by_account.get(name, []):
|
||||
for period in period_list:
|
||||
entry.posting_date = getdate(entry.posting_date)
|
||||
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
def calculate_values(accounts_by_name, gl_entries_by_account, period_list):
|
||||
for entries in gl_entries_by_account.values():
|
||||
for entry in entries:
|
||||
d = accounts_by_name.get(entry.account)
|
||||
for period in period_list:
|
||||
# check if posting date is within the period
|
||||
if entry.posting_date <= period.to_date:
|
||||
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||
|
||||
|
||||
def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
|
||||
@@ -159,22 +157,8 @@ def add_total_row(out, balance_must_be, period_list):
|
||||
out.append({})
|
||||
|
||||
def get_accounts(company, root_type):
|
||||
# root lft, rgt
|
||||
root_account = frappe.db.sql("""select lft, rgt from `tabAccount`
|
||||
where company=%s and root_type=%s and ifnull(parent_account, '') = ''
|
||||
order by lft limit 1""",
|
||||
(company, root_type), as_dict=True)
|
||||
|
||||
if not root_account:
|
||||
return None
|
||||
|
||||
lft, rgt = root_account[0].lft, root_account[0].rgt
|
||||
|
||||
accounts = frappe.db.sql("""select * from `tabAccount`
|
||||
where company=%(company)s and lft >= %(lft)s and rgt <= %(rgt)s order by lft""",
|
||||
{ "company": company, "lft": lft, "rgt": rgt }, as_dict=True)
|
||||
|
||||
return accounts
|
||||
return frappe.db.sql("""select name, parent_account, lft, rgt, root_type, report_type, account_name from `tabAccount`
|
||||
where company=%s and root_type=%s order by lft""", (company, root_type), as_dict=True)
|
||||
|
||||
def filter_accounts(accounts, depth=10):
|
||||
parent_children_map = {}
|
||||
@@ -196,14 +180,6 @@ def filter_accounts(accounts, depth=10):
|
||||
filtered_accounts.append(child)
|
||||
add_to_list(child.name, level + 1)
|
||||
|
||||
else:
|
||||
# include all children at level lower than the depth
|
||||
parent_account = accounts_by_name[parent]
|
||||
parent_account["collapsed_children"] = []
|
||||
for d in accounts:
|
||||
if d.lft > parent_account.lft and d.rgt < parent_account.rgt:
|
||||
parent_account["collapsed_children"].append(d.name)
|
||||
|
||||
add_to_list(None, 0)
|
||||
|
||||
return filtered_accounts, accounts_by_name
|
||||
@@ -234,7 +210,7 @@ def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closi
|
||||
if from_date:
|
||||
additional_conditions.append("and posting_date >= %(from_date)s")
|
||||
|
||||
gl_entries = frappe.db.sql("""select * from `tabGL Entry`
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening from `tabGL Entry`
|
||||
where company=%(company)s
|
||||
{additional_conditions}
|
||||
and posting_date <= %(to_date)s
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.utils import flt, getdate
|
||||
from frappe.utils import flt, getdate, cstr
|
||||
from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
@@ -66,7 +66,7 @@ def get_gl_entries(filters):
|
||||
|
||||
gl_entries = frappe.db.sql("""select posting_date, account, party_type, party,
|
||||
sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit,
|
||||
voucher_type, voucher_no, cost_center, remarks, is_opening, against
|
||||
voucher_type, voucher_no, cost_center, remarks, against, is_opening
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s {conditions}
|
||||
{group_by_condition}
|
||||
@@ -91,6 +91,9 @@ def get_conditions(filters):
|
||||
|
||||
if filters.get("party"):
|
||||
conditions.append("party=%(party)s")
|
||||
|
||||
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
|
||||
conditions.append("posting_date >=%(from_date)s")
|
||||
|
||||
from frappe.desk.reportview import build_match_conditions
|
||||
match_conditions = build_match_conditions("GL Entry")
|
||||
@@ -148,14 +151,15 @@ def initialize_gle_map(gl_entries):
|
||||
|
||||
def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
opening, total_debit, total_credit = 0, 0, 0
|
||||
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
for gle in gl_entries:
|
||||
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
|
||||
if gle.posting_date < getdate(filters.from_date):
|
||||
if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \
|
||||
and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):
|
||||
gle_map[gle.account].opening += amount
|
||||
if filters.get("account") or filters.get("party"):
|
||||
opening += amount
|
||||
elif gle.posting_date <= getdate(filters.to_date):
|
||||
elif gle.posting_date <= to_date:
|
||||
gle_map[gle.account].entries.append(gle)
|
||||
gle_map[gle.account].total_debit += flt(gle.debit, 3)
|
||||
gle_map[gle.account].total_credit += flt(gle.credit, 3)
|
||||
|
||||
@@ -14,7 +14,7 @@ def execute(filters=None):
|
||||
source = gross_profit_data.grouped_data if filters.get("group_by") != "Invoice" else gross_profit_data.data
|
||||
|
||||
group_wise_columns = frappe._dict({
|
||||
"invoice": ["parent", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \
|
||||
"invoice": ["parent", "customer", "posting_date", "posting_time", "item_code", "item_name", "brand", "description", \
|
||||
"warehouse", "qty", "base_rate", "buying_rate", "base_amount",
|
||||
"buying_amount", "gross_profit", "gross_profit_percent", "project"],
|
||||
"item_code": ["item_code", "item_name", "brand", "description", "warehouse", "qty", "base_rate",
|
||||
@@ -175,16 +175,15 @@ class GrossProfitGenerator(object):
|
||||
|
||||
else:
|
||||
if row.update_stock or row.dn_detail:
|
||||
parenttype, parent, item_row = row.parenttype, row.parent, row.item_row
|
||||
if row.dn_detail:
|
||||
row.parenttype = "Delivery Note"
|
||||
row.parent = row.delivery_note
|
||||
row.item_row = row.dn_detail
|
||||
parenttype, parent, item_row = "Delivery Note", row.delivery_note, row.dn_detail
|
||||
|
||||
my_sle = self.sle.get((item_code, row.warehouse))
|
||||
for i, sle in enumerate(my_sle):
|
||||
# find the stock valution rate from stock ledger entry
|
||||
if sle.voucher_type == row.parenttype and row.parent == sle.voucher_no and \
|
||||
sle.voucher_detail_no == row.item_row:
|
||||
if sle.voucher_type == parenttype and parent == sle.voucher_no and \
|
||||
sle.voucher_detail_no == item_row:
|
||||
previous_stock_value = len(my_sle) > i+1 and \
|
||||
flt(my_sle[i+1].stock_value) or 0.0
|
||||
return previous_stock_value - flt(sle.stock_value)
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
|
||||
frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
@@ -23,27 +31,28 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = {
|
||||
default: "Incoming"
|
||||
},
|
||||
{
|
||||
fieldname:"account",
|
||||
label: __("Account"),
|
||||
fieldtype: "Link",
|
||||
options: "Account",
|
||||
get_query: function() {
|
||||
"fieldname":"party_type",
|
||||
"label": __("Party Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"get_query": function() {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_account_list",
|
||||
filters: {
|
||||
"report_type": "Balance Sheet",
|
||||
company: frappe.query_report.filters_by_name.company.get_value()
|
||||
}
|
||||
filters: {"name": ["in", ["Customer", "Supplier"]]}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname:"company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("company")
|
||||
"fieldname":"party",
|
||||
"label": __("Party"),
|
||||
"fieldtype": "Dynamic Link",
|
||||
"get_options": function() {
|
||||
var party_type = frappe.query_report.filters_by_name.party_type.get_value();
|
||||
var party = frappe.query_report.filters_by_name.party.get_value();
|
||||
if(party && !party_type) {
|
||||
frappe.throw(__("Please select Party Type first"));
|
||||
}
|
||||
return party_type;
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
columns = get_columns()
|
||||
validate_filters(filters)
|
||||
|
||||
columns = get_columns(filters)
|
||||
entries = get_entries(filters)
|
||||
invoice_posting_date_map = get_invoice_posting_date_map(filters)
|
||||
against_date = ""
|
||||
@@ -20,67 +21,72 @@ def execute(filters=None):
|
||||
for d in entries:
|
||||
if d.against_voucher:
|
||||
against_date = d.against_voucher and invoice_posting_date_map[d.against_voucher] or ""
|
||||
outstanding_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
payment_amount = flt(d.debit) or -1 * flt(d.credit)
|
||||
else:
|
||||
against_date = d.against_invoice and invoice_posting_date_map[d.against_invoice] or ""
|
||||
outstanding_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
payment_amount = flt(d.credit) or -1 * flt(d.debit)
|
||||
|
||||
row = [d.name, d.account, d.posting_date, d.against_voucher or d.against_invoice,
|
||||
row = [d.name, d.party_type, d.party, d.posting_date, d.against_voucher or d.against_invoice,
|
||||
against_date, d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
|
||||
|
||||
if d.against_voucher or d.against_invoice:
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, outstanding_amount)
|
||||
row += get_ageing_data(30, 60, 90, d.posting_date, against_date, payment_amount)
|
||||
else:
|
||||
row += ["", "", "", "", ""]
|
||||
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
|
||||
def validate_filters(filters):
|
||||
if (filters.get("payment_type") == "Incoming" and filters.get("party_type") == "Supplier") or \
|
||||
(filters.get("payment_type") == "Outgoing" and filters.get("party_type") == "Customer"):
|
||||
frappe.throw(_("{0} payment entries can not be filtered by {1}")\
|
||||
.format(filters.payment_type, filters.party_type))
|
||||
|
||||
def get_columns():
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140", _("Account") + ":Link/Account:140",
|
||||
_("Posting Date") + ":Date:100", _("Against Invoice") + ":Link/Purchase Invoice:130",
|
||||
def get_columns(filters):
|
||||
return [_("Journal Entry") + ":Link/Journal Entry:140",
|
||||
_("Party Type") + ":Link/DocType:100", _("Party") + ":Dynamic Link/Party Type:140",
|
||||
_("Posting Date") + ":Date:100",
|
||||
_("Against Invoice") + (":Link/Purchase Invoice:130" if filters.get("payment_type") == "Outgoing" else ":Link/Sales 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):
|
||||
conditions = ""
|
||||
party = None
|
||||
conditions = []
|
||||
|
||||
if filters.get("account"):
|
||||
party = filters["account"]
|
||||
else:
|
||||
conditions += " and company = '%s'" % frappe.db.escape(filters["company"])
|
||||
if not filters.get("party_type"):
|
||||
if filters.get("payment_type") == "Outgoing":
|
||||
filters["party_type"] = "Supplier"
|
||||
else:
|
||||
filters["party_type"] = "Customer"
|
||||
|
||||
if filters.get("party_type"):
|
||||
conditions.append("jvd.party_type=%(party_type)s")
|
||||
|
||||
account_type = "Receivable" if filters.get("payment_type") == "Incoming" else "Payable"
|
||||
if filters.get("party"):
|
||||
conditions.append("jvd.party=%(party)s")
|
||||
|
||||
conditions += """ and account in
|
||||
(select name from tabAccount
|
||||
where account_type = '{0}'
|
||||
and company='{1}')""".format(account_type, frappe.db.escape(filters["company"]))
|
||||
|
||||
if party:
|
||||
conditions += " and jvd.party = '%s'" % frappe.db.escape(party)
|
||||
else:
|
||||
conditions += " and ifnull(jvd.party, '') != ''"
|
||||
if filters.get("company"):
|
||||
conditions.append("jv.company=%(company)s")
|
||||
|
||||
if filters.get("from_date"):
|
||||
conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
|
||||
conditions.append("jv.posting_date >= %(from_date)s")
|
||||
if filters.get("to_date"):
|
||||
conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
|
||||
conditions.append("jv.posting_date <= %(to_date)s")
|
||||
|
||||
return conditions
|
||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||
|
||||
def get_entries(filters):
|
||||
conditions = get_conditions(filters)
|
||||
entries = frappe.db.sql("""select jv.name, jvd.account, jv.posting_date,
|
||||
entries = frappe.db.sql("""select jv.name, jvd.party_type, jvd.party, jv.posting_date,
|
||||
jvd.against_voucher, jvd.against_invoice, jvd.debit, jvd.credit,
|
||||
jv.cheque_no, jv.cheque_date, jv.remark
|
||||
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
|
||||
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
|
||||
conditions, as_dict=1, debug=1)
|
||||
conditions, filters, as_dict=1)
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ def execute(filters=None):
|
||||
invoice_list = get_invoices(filters)
|
||||
columns, expense_accounts, tax_accounts = get_columns(invoice_list)
|
||||
|
||||
|
||||
if not invoice_list:
|
||||
msgprint(_("No record found"))
|
||||
return columns, invoice_list
|
||||
@@ -30,7 +29,8 @@ def execute(filters=None):
|
||||
purchase_receipt = list(set(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", [])))
|
||||
project_name = list(set(invoice_po_pr_map.get(inv.name, {}).get("project_name", [])))
|
||||
|
||||
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name, supplier_details.get(inv.supplier),
|
||||
row = [inv.name, inv.posting_date, inv.supplier, inv.supplier_name,
|
||||
supplier_details.get(inv.supplier),
|
||||
inv.credit_to, ", ".join(project_name), inv.bill_no, inv.bill_date, inv.remarks,
|
||||
", ".join(purchase_order), ", ".join(purchase_receipt)]
|
||||
|
||||
@@ -54,8 +54,7 @@ def execute(filters=None):
|
||||
|
||||
# total tax, grand total, outstanding amount & rounded total
|
||||
row += [total_tax, inv.base_grand_total, flt(inv.base_grand_total, 2), inv.outstanding_amount]
|
||||
data.append(row)
|
||||
# raise Exception
|
||||
data.append(row)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -107,7 +106,7 @@ def get_conditions(filters):
|
||||
|
||||
def get_invoices(filters):
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name
|
||||
return frappe.db.sql("""select name, posting_date, credit_to, supplier, supplier_name,
|
||||
bill_no, bill_date, remarks, base_net_total, base_grand_total, outstanding_amount
|
||||
from `tabPurchase Invoice` where docstatus = 1 %s
|
||||
order by posting_date desc, name desc""" % conditions, filters, as_dict=1)
|
||||
|
||||
@@ -30,7 +30,8 @@ def execute(filters=None):
|
||||
delivery_note = list(set(invoice_so_dn_map.get(inv.name, {}).get("delivery_note", [])))
|
||||
|
||||
row = [inv.name, inv.posting_date, inv.customer, inv.customer_name,
|
||||
customer_map.get(inv.customer)["customer_group"], customer_map.get(inv.customer)["territory"],
|
||||
customer_map.get(inv.customer, {}).get("customer_group"),
|
||||
customer_map.get(inv.customer, {}).get("territory"),
|
||||
inv.debit_to, inv.project_name, inv.remarks, ", ".join(sales_order), ", ".join(delivery_note)]
|
||||
|
||||
# map income values
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, getdate, formatdate
|
||||
from frappe.utils import cint, flt, getdate, formatdate, cstr
|
||||
from erpnext.accounts.report.financial_statements import filter_accounts, get_gl_entries
|
||||
|
||||
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
|
||||
|
||||
def execute(filters):
|
||||
def execute(filters=None):
|
||||
validate_filters(filters)
|
||||
data = get_data(filters)
|
||||
columns = get_columns()
|
||||
@@ -45,8 +45,8 @@ def validate_filters(filters):
|
||||
filters.to_date = filters.year_end_date
|
||||
|
||||
def get_data(filters):
|
||||
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""",
|
||||
filters.company, as_dict=True)
|
||||
accounts = frappe.db.sql("""select name, parent_account, account_name, root_type, report_type, lft, rgt
|
||||
from `tabAccount` where company=%s order by lft""", filters.company, as_dict=True)
|
||||
|
||||
if not accounts:
|
||||
return None
|
||||
@@ -56,17 +56,58 @@ def get_data(filters):
|
||||
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
|
||||
where company=%s""", (filters.company,))[0]
|
||||
|
||||
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt,
|
||||
gl_entries_by_account = get_gl_entries(filters.company, filters.from_date, filters.to_date, min_lft, max_rgt,
|
||||
ignore_closing_entries=not flt(filters.with_period_closing_entry))
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, filters)
|
||||
opening_balances = get_opening_balances(filters)
|
||||
|
||||
total_row = calculate_values(accounts, gl_entries_by_account, opening_balances, filters)
|
||||
accumulate_values_into_parents(accounts, accounts_by_name)
|
||||
|
||||
data = prepare_data(accounts, filters, total_row)
|
||||
|
||||
return data
|
||||
|
||||
def get_opening_balances(filters):
|
||||
balance_sheet_opening = get_rootwise_opening_balances(filters, "Balance Sheet")
|
||||
pl_opening = get_rootwise_opening_balances(filters, "Profit and Loss")
|
||||
|
||||
balance_sheet_opening.update(pl_opening)
|
||||
return balance_sheet_opening
|
||||
|
||||
|
||||
def get_rootwise_opening_balances(filters, report_type):
|
||||
additional_conditions = " and posting_date >= %(year_start_date)s" \
|
||||
if report_type == "Profit and Loss" else ""
|
||||
|
||||
if not flt(filters.with_period_closing_entry):
|
||||
additional_conditions += " and ifnull(voucher_type, '')!='Period Closing Voucher'"
|
||||
|
||||
gle = frappe.db.sql("""
|
||||
select
|
||||
account, sum(ifnull(debit, 0)) as opening_debit, sum(ifnull(credit, 0)) as opening_credit
|
||||
from `tabGL Entry`
|
||||
where
|
||||
company=%(company)s
|
||||
{additional_conditions}
|
||||
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
|
||||
and account in (select name from `tabAccount` where report_type=%(report_type)s)
|
||||
group by account""".format(additional_conditions=additional_conditions),
|
||||
{
|
||||
"company": filters.company,
|
||||
"from_date": filters.from_date,
|
||||
"report_type": report_type,
|
||||
"year_start_date": filters.year_start_date
|
||||
},
|
||||
as_dict=True)
|
||||
|
||||
opening = frappe._dict()
|
||||
for d in gle:
|
||||
opening.setdefault(d.account, d)
|
||||
|
||||
return opening
|
||||
|
||||
def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
def calculate_values(accounts, gl_entries_by_account, opening_balances, filters):
|
||||
init = {
|
||||
"opening_debit": 0.0,
|
||||
"opening_credit": 0.0,
|
||||
@@ -87,30 +128,18 @@ def calculate_values(accounts, gl_entries_by_account, filters):
|
||||
for d in accounts:
|
||||
d.update(init.copy())
|
||||
|
||||
# add opening
|
||||
d["opening_debit"] = opening_balances.get(d.name, {}).get("opening_debit", 0)
|
||||
d["opening_credit"] = opening_balances.get(d.name, {}).get("opening_credit", 0)
|
||||
|
||||
for entry in gl_entries_by_account.get(d.name, []):
|
||||
posting_date = getdate(entry.posting_date)
|
||||
|
||||
# opening
|
||||
if posting_date < filters.from_date:
|
||||
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
|
||||
(filters.year_start_date <= posting_date < filters.from_date))
|
||||
|
||||
if is_valid_opening:
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
elif posting_date <= filters.to_date:
|
||||
|
||||
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
|
||||
d["opening_debit"] += flt(entry.debit)
|
||||
d["opening_credit"] += flt(entry.credit)
|
||||
|
||||
else:
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
if cstr(entry.is_opening) != "Yes":
|
||||
d["debit"] += flt(entry.debit)
|
||||
d["credit"] += flt(entry.credit)
|
||||
|
||||
total_row["debit"] += d["debit"]
|
||||
total_row["credit"] += d["credit"]
|
||||
|
||||
|
||||
return total_row
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None):
|
||||
# different filter for group and ledger - improved performance
|
||||
if acc.is_group:
|
||||
cond.append("""exists (
|
||||
select * from `tabAccount` ac where ac.name = gle.account
|
||||
select name from `tabAccount` ac where ac.name = gle.account
|
||||
and ac.lft >= %s and ac.rgt <= %s
|
||||
)""" % (acc.lft, acc.rgt))
|
||||
else:
|
||||
@@ -397,7 +397,7 @@ def get_outstanding_invoices(amount_query, account, party_type, party):
|
||||
|
||||
for d in outstanding_voucher_list:
|
||||
payment_amount = frappe.db.sql("""
|
||||
select ifnull(sum(ifnull({amount_query}, 0)), 0)
|
||||
select ifnull(sum({amount_query}), 0)
|
||||
from
|
||||
`tabGL Entry`
|
||||
where
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"description": "Supplier (vendor) name as entered in supplier master",
|
||||
"description": "",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
@@ -457,7 +457,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -868,12 +868,21 @@
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"fieldname": "recurring_print_format",
|
||||
"fieldtype": "Link",
|
||||
"label": "Recurring Print Format",
|
||||
"options": "Print Format",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-05-27 02:48:02.452899",
|
||||
"modified": "2015-06-22 07:30:36.259753",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -538,7 +538,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:16.553472",
|
||||
"modified": "2015-06-02 14:19:21.459032",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item",
|
||||
|
||||
@@ -57,3 +57,7 @@ cur_frm.fields_dict['item_serial_no'].get_query = function(doc, cdt, cdn) {
|
||||
|
||||
return { filters: filter }
|
||||
}
|
||||
|
||||
cur_frm.add_fetch('item_code', 'item_name', 'item_name');
|
||||
cur_frm.add_fetch('item_code', 'description', 'description');
|
||||
|
||||
|
||||
@@ -127,6 +127,14 @@
|
||||
"permlevel": 0,
|
||||
"width": "50%"
|
||||
},
|
||||
{
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Item Name",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
@@ -219,7 +227,7 @@
|
||||
"icon": "icon-search",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-04-14 07:37:07.331291",
|
||||
"modified": "2015-06-08 02:40:25.121948",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Quality Inspection",
|
||||
|
||||
@@ -31,7 +31,6 @@ class QualityInspection(Document):
|
||||
(self.name, self.modified, self.purchase_receipt_no,
|
||||
self.item_code))
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
if self.purchase_receipt_no:
|
||||
frappe.db.sql("""update `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2
|
||||
@@ -39,7 +38,6 @@ class QualityInspection(Document):
|
||||
where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name""",
|
||||
(self.modified, self.purchase_receipt_no, self.item_code))
|
||||
|
||||
|
||||
def item_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
if filters.get("from"):
|
||||
from frappe.desk.reportview import get_match_cond
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"description": "Supplier (vendor) name as entered in supplier master",
|
||||
"description": "",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
@@ -439,7 +439,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -660,7 +660,7 @@
|
||||
"icon": "icon-shopping-cart",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2015-05-27 02:48:02.098540",
|
||||
"modified": "2015-06-15 15:39:08.954248",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -413,7 +413,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:15.853886",
|
||||
"modified": "2015-06-02 14:19:33.922968",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation Item",
|
||||
|
||||
17
erpnext/change_log/v5/v5_0_25.md
Normal file
17
erpnext/change_log/v5/v5_0_25.md
Normal file
@@ -0,0 +1,17 @@
|
||||
- Performance upgrade in Trial Balance, General Ledger, AR/AP, Balance Sheet and P&L Statement reports
|
||||
- Add index on Account and GL Entry, Sales Invoice and Purchase Invoice table
|
||||
- Don't create Time Logs against Production Order if Workstation is not specified in Operations
|
||||
- Task should be mandatory in Time Log only when Project is mentioned but Production Order is not
|
||||
- Supplier invoice no unique validation and supplier invoice date can not be after posting date
|
||||
- Removed BOM No from mandatory from Stock Entry against Production Order
|
||||
- Load tasks in project for printing purpose
|
||||
- Added Customers Not Buying Since Long Time against Sales Invoice
|
||||
- POS - search by Item Group
|
||||
- Payment period based on invoice date: show party columns and filter based on party
|
||||
- Barcode added to Purchase Receipt
|
||||
- Fetch item name and desc on change of item code in Quality Inspection
|
||||
- Show item name in item grid view based 'In List View' property
|
||||
- Validate and update manufactured qty in Stock Entry
|
||||
- Show only users with Expense Approver role in Expense Claim Approver field
|
||||
- Over Production Allowance Percentage Setting added to Manufacturing Settings
|
||||
- Activity Cost - Mandatory removed for Employee
|
||||
1
erpnext/change_log/v5/v5_0_28.md
Normal file
1
erpnext/change_log/v5/v5_0_28.md
Normal file
@@ -0,0 +1 @@
|
||||
- Open notification of Sales Order and Purchase Order based on whether Invoice is created against them. For eg. If a Sales Order is not Invoiced, it will be considered as open. Previously it was considered open if Delivery Note was created against Sales Order.
|
||||
8
erpnext/change_log/v5_1_0.md
Normal file
8
erpnext/change_log/v5_1_0.md
Normal file
@@ -0,0 +1,8 @@
|
||||
- Item variants is now manageable via dedicated tool **Manage Variants**. To learn about it, check https://manual.erpnext.com/contents/stock/item/item-variants
|
||||
- Against account in General Ledger will show Party instead of Account (which is not useful)
|
||||
- Print format for recurring documents can be set by the users
|
||||
- Recurring documents won't be created for Stopped Sales / Purchase Orders.
|
||||
- Lead status will be changed to 'Opportunity' when Lead converted to Opportunity
|
||||
- Amount in Journal Entry list view
|
||||
- Currency exchange rate is now automatically fetched from fixer.io, instead of jsonrates.com
|
||||
- Item image is now available in Sales / Purchase Invoice
|
||||
@@ -103,6 +103,12 @@ def get_data():
|
||||
"name": "Completed Production Orders",
|
||||
"doctype": "Production Order"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "BOM Search",
|
||||
"doctype": "BOM"
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -237,6 +237,12 @@ def get_data():
|
||||
"route": "query-report/Sales Person Target Variance Item Group-Wise",
|
||||
"doctype": "Sales Person",
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "BOM Search",
|
||||
"doctype": "BOM"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
|
||||
@@ -38,7 +38,8 @@ class AccountsController(TransactionBase):
|
||||
convert_to_recurring(self, self.get("posting_date") or self.get("transaction_date"))
|
||||
|
||||
def before_recurring(self):
|
||||
self.fiscal_year = None
|
||||
if self.meta.get_field("fiscal_year"):
|
||||
self.fiscal_year = None
|
||||
if self.meta.get_field("due_date"):
|
||||
self.due_date = None
|
||||
|
||||
@@ -46,7 +47,7 @@ class AccountsController(TransactionBase):
|
||||
for fieldname in ["posting_date", "transaction_date"]:
|
||||
if not self.get(fieldname) and self.meta.get_field(fieldname):
|
||||
self.set(fieldname, today())
|
||||
if not self.fiscal_year:
|
||||
if self.meta.get_field("fiscal_year") and not self.fiscal_year:
|
||||
self.fiscal_year = get_fiscal_year(self.get(fieldname))[0]
|
||||
break
|
||||
|
||||
@@ -334,7 +335,7 @@ class AccountsController(TransactionBase):
|
||||
@frappe.whitelist()
|
||||
def get_tax_rate(account_head):
|
||||
return frappe.db.get_value("Account", account_head, "tax_rate")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_default_taxes_and_charges(master_doctype):
|
||||
default_tax = frappe.db.get_value(master_doctype, {"is_default": 1})
|
||||
|
||||
@@ -194,7 +194,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
|
||||
and tabBOM.is_active=1
|
||||
and tabBOM.%(key)s like "%(txt)s"
|
||||
%(fcond)s %(mcond)s
|
||||
limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % txt,
|
||||
limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % frappe.db.escape(txt),
|
||||
'fcond': get_filters_cond(doctype, filters, conditions),
|
||||
'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
|
||||
|
||||
@@ -207,7 +207,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
|
||||
where `tabProject`.status not in ("Completed", "Cancelled")
|
||||
and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s
|
||||
order by `tabProject`.name asc
|
||||
limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % txt,
|
||||
limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % frappe.db.escape(txt),
|
||||
'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len})
|
||||
|
||||
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
||||
@@ -33,11 +33,13 @@ def manage_recurring_documents(doctype, next_date=None, commit=True):
|
||||
next_date = next_date or nowdate()
|
||||
|
||||
date_field = date_field_map[doctype]
|
||||
|
||||
condition = " and ifnull(status, '') != 'Stopped'" if doctype in ("Sales Order", "Purchase Order") else ""
|
||||
|
||||
recurring_documents = frappe.db.sql("""select name, recurring_id
|
||||
from `tab{}` where ifnull(is_recurring, 0)=1
|
||||
and docstatus=1 and next_date='{}'
|
||||
and next_date <= ifnull(end_date, '2199-12-31')""".format(doctype, next_date))
|
||||
from `tab{0}` where ifnull(is_recurring, 0)=1
|
||||
and docstatus=1 and next_date=%s
|
||||
and next_date <= ifnull(end_date, '2199-12-31') {1}""".format(doctype, condition), next_date)
|
||||
|
||||
exception_list = []
|
||||
for ref_document, recurring_id in recurring_documents:
|
||||
@@ -124,7 +126,7 @@ def send_notification(new_rv):
|
||||
frappe.sendmail(new_rv.notification_email_address,
|
||||
subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
|
||||
message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
|
||||
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name)])
|
||||
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=new_rv.recurring_print_format)])
|
||||
|
||||
def notify_errors(doc, doctype, party, owner):
|
||||
from frappe.utils.user import get_system_managers
|
||||
|
||||
@@ -78,7 +78,7 @@ class StatusUpdater(Document):
|
||||
self.status = s[0]
|
||||
break
|
||||
|
||||
if self.status != _status:
|
||||
if self.status != _status and self.status not in ("Submitted", "Cancelled"):
|
||||
self.add_comment("Label", _(self.status))
|
||||
|
||||
if update:
|
||||
|
||||
@@ -75,8 +75,7 @@ class Lead(SellingController):
|
||||
return frappe.db.get_value("Customer", {"lead_name": self.name})
|
||||
|
||||
def has_opportunity(self):
|
||||
return frappe.db.get_value("Opportunity", {"lead": self.name, "docstatus": 1,
|
||||
"status": ["!=", "Lost"]})
|
||||
return frappe.db.get_value("Opportunity", {"lead": self.name, "status": ["!=", "Lost"]})
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_customer(source_name, target_doc=None):
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
@@ -134,7 +134,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-14 14:55:18.325286",
|
||||
"modified": "2015-06-02 14:18:16.622288",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Opportunity Item",
|
||||
|
||||
@@ -5,7 +5,7 @@ app_publisher = "Frappe 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 = "5.0.14"
|
||||
app_version = "5.1.0"
|
||||
|
||||
error_report_email = "support@erpnext.com"
|
||||
|
||||
@@ -38,16 +38,14 @@ website_route_rules = [
|
||||
{"from_route": "/invoices", "to_route": "Sales Invoice"},
|
||||
{"from_route": "/invoices/<path:name>", "to_route": "print", "defaults": {"doctype": "Sales Invoice"}},
|
||||
{"from_route": "/shipments", "to_route": "Delivery Note"},
|
||||
{"from_route": "/shipments/<path:name>", "to_route": "print", "defaults": {"doctype": "Delivery Note"}},
|
||||
{"from_route": "/issues", "to_route": "Issue"},
|
||||
{"from_route": "/issues/<path:name>", "to_route": "print", "defaults": {"doctype": "Issue"}},
|
||||
{"from_route": "/addresses", "to_route": "Address"},
|
||||
{"from_route": "/shipments/<path:name>", "to_route": "print", "defaults": {"doctype": "Delivery Note"}}
|
||||
]
|
||||
|
||||
has_website_permission = {
|
||||
"Sales Order": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission"
|
||||
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
|
||||
"Issue": "erpnext.support.doctype.issue.issue.has_website_permission"
|
||||
}
|
||||
|
||||
dump_report_map = "erpnext.startup.report_data_map.data_map"
|
||||
@@ -80,8 +78,10 @@ doc_events = {
|
||||
}
|
||||
|
||||
scheduler_events = {
|
||||
"hourly": [
|
||||
"erpnext.controllers.recurring_document.create_recurring_documents"
|
||||
],
|
||||
"daily": [
|
||||
"erpnext.controllers.recurring_document.create_recurring_documents",
|
||||
"erpnext.stock.reorder_item.reorder_item",
|
||||
"erpnext.setup.doctype.email_digest.email_digest.send",
|
||||
"erpnext.support.doctype.issue.issue.auto_close_tickets",
|
||||
|
||||
@@ -63,7 +63,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn) {
|
||||
|
||||
cur_frm.set_query("exp_approver", function() {
|
||||
return {
|
||||
filters: [["UserRole", "role", "=", "Expense Approver"]]
|
||||
query: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_approver"
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,4 +58,13 @@ class ExpenseClaim(Document):
|
||||
def validate_sanctioned_amount(self):
|
||||
for d in self.get('expenses'):
|
||||
if flt(d.sanctioned_amount) > flt(d.claim_amount):
|
||||
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
|
||||
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_expense_approver(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""
|
||||
select u.name, concat(u.first_name, ' ', u.last_name)
|
||||
from tabUser u, tabUserRole r
|
||||
where u.name = r.parent and r.role = 'Expense Approver' and u.name like %s
|
||||
""", ("%" + txt + "%"))
|
||||
@@ -339,6 +339,7 @@ def add_block_dates(events, start, end, employee, company):
|
||||
events.append({
|
||||
"doctype": "Leave Block List Date",
|
||||
"from_date": block_date.block_date,
|
||||
"to_date": block_date.block_date,
|
||||
"title": _("Leave Blocked") + ": " + block_date.reason,
|
||||
"name": "_" + str(cnt),
|
||||
})
|
||||
@@ -355,6 +356,7 @@ def add_holidays(events, start, end, employee, company):
|
||||
events.append({
|
||||
"doctype": "Holiday",
|
||||
"from_date": holiday.holiday_date,
|
||||
"to_date": holiday.holiday_date,
|
||||
"title": _("Holiday") + ": " + cstr(holiday.description),
|
||||
"name": holiday.name
|
||||
})
|
||||
|
||||
@@ -24,4 +24,8 @@ cur_frm.cscript.to_date = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.allocation_type = function (doc, cdt, cdn){
|
||||
doc.no_of_days = '';
|
||||
refresh_field('no_of_days');
|
||||
}
|
||||
}
|
||||
|
||||
frappe.ui.form.on("Leave Control Panel", "refresh", function(frm) {
|
||||
frm.disable_save();
|
||||
});
|
||||
@@ -94,11 +94,11 @@
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"hide_toolbar": 1,
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-05 05:11:40.791976",
|
||||
"modified": "2015-06-05 11:38:19.994852",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Leave Control Panel",
|
||||
@@ -110,7 +110,7 @@
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
|
||||
@@ -43,3 +43,8 @@ cur_frm.cscript.make_jv = function(doc, dt, dn) {
|
||||
frappe.set_route("Form", doc.doctype, doc.name);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
|
||||
frm.disable_save();
|
||||
});
|
||||
@@ -150,10 +150,11 @@
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"icon": "icon-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-25 07:21:04.778082",
|
||||
"modified": "2015-06-05 11:33:00.152362",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Salary Manager",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import cstr, flt
|
||||
from frappe.utils import cstr, flt, getdate
|
||||
from frappe.model.naming import make_autoname
|
||||
from frappe import _
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
@@ -14,6 +14,13 @@ from erpnext.hr.utils import set_employee_name
|
||||
class SalaryStructure(Document):
|
||||
def autoname(self):
|
||||
self.name = make_autoname(self.employee + '/.SST' + '/.#####')
|
||||
|
||||
def validate(self):
|
||||
self.check_existing()
|
||||
self.validate_amount()
|
||||
self.validate_employee()
|
||||
self.validate_joining_date()
|
||||
set_employee_name(self)
|
||||
|
||||
def get_employee_details(self):
|
||||
ret = {}
|
||||
@@ -77,14 +84,11 @@ class SalaryStructure(Document):
|
||||
old_employee = frappe.db.get_value("Salary Structure", self.name, "employee")
|
||||
if old_employee and self.employee != old_employee:
|
||||
frappe.throw(_("Employee can not be changed"))
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.check_existing()
|
||||
self.validate_amount()
|
||||
self.validate_employee()
|
||||
set_employee_name(self)
|
||||
|
||||
|
||||
def validate_joining_date(self):
|
||||
joining_date = getdate(frappe.db.get_value("Employee", self.employee, "date_of_joining"))
|
||||
if getdate(self.from_date) < joining_date:
|
||||
frappe.throw(_("From Date in Salary Structure cannot be lesser than Employee Joining Date."))
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_salary_slip(source_name, target_doc=None):
|
||||
|
||||
@@ -12,6 +12,7 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.frm.disable_save();
|
||||
this.show_upload();
|
||||
},
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"creation": "2013-01-25 11:34:53",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
@@ -53,11 +54,13 @@
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 1,
|
||||
"icon": "icon-upload-alt",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"max_attachments": 1,
|
||||
"modified": "2015-02-05 05:11:48.540845",
|
||||
"modified": "2015-06-05 11:37:04.348120",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Upload Attendance",
|
||||
@@ -65,25 +68,25 @@
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "HR User",
|
||||
"share": 1,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.item_code) {
|
||||
return frappe.call({
|
||||
doc: cur_frm.doc,
|
||||
doc: doc,
|
||||
method: "get_bom_material_detail",
|
||||
args: {
|
||||
'item_code': d.item_code,
|
||||
@@ -234,5 +234,3 @@ frappe.ui.form.on("BOM", "with_operations", function(frm) {
|
||||
cur_frm.cscript.image = function() {
|
||||
refresh_field("image_view");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"fieldname": "item",
|
||||
"fieldtype": "Link",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Item",
|
||||
"oldfieldname": "item",
|
||||
"oldfieldtype": "Link",
|
||||
@@ -54,7 +54,7 @@
|
||||
"fieldname": "is_active",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Is Active",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "is_active",
|
||||
@@ -67,7 +67,7 @@
|
||||
"default": "1",
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 0,
|
||||
"in_list_view": 1,
|
||||
"label": "Is Default",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "is_default",
|
||||
@@ -279,7 +279,7 @@
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-03-03 14:22:44.725097",
|
||||
"modified": "2015-06-26 02:02:30.705279",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM",
|
||||
|
||||
@@ -425,5 +425,5 @@ def validate_bom_no(item, bom_no):
|
||||
if not getattr(frappe.flags, "in_test", False):
|
||||
frappe.throw(_("BOM {0} must be submitted").format(bom_no))
|
||||
if item and not (bom.item.lower() == item.lower() or \
|
||||
bom.item.lower() == frappe.db.get_value("Item", item, "variant_of").lower()):
|
||||
bom.item.lower() == cstr(frappe.db.get_value("Item", item, "variant_of")).lower()):
|
||||
frappe.throw(_("BOM {0} does not belong to Item {1}").format(bom_no, item))
|
||||
|
||||
@@ -55,6 +55,13 @@
|
||||
"label": "Time Between Operations (in mins)",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "over_production_allowance_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Over Production Allowance Percentage",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
@@ -65,7 +72,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"modified": "2015-04-21 07:57:40.260862",
|
||||
"modified": "2015-06-15 05:52:22.986958",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Manufacturing Settings",
|
||||
|
||||
@@ -90,8 +90,9 @@ class ProductionOrder(Document):
|
||||
(self.sales_order, self.production_item))[0][0]
|
||||
# total qty in SO
|
||||
so_qty = flt(so_item_qty) + flt(dnpi_qty)
|
||||
|
||||
if total_qty > so_qty:
|
||||
|
||||
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings", "over_production_allowance_percentage"))
|
||||
if total_qty > so_qty + (allowance_percentage/100 * so_qty):
|
||||
frappe.throw(_("Cannot produce more Item {0} than Sales Order quantity {1}").format(self.production_item,
|
||||
so_qty), OverProductionError)
|
||||
|
||||
@@ -217,12 +218,14 @@ class ProductionOrder(Document):
|
||||
for i, d in enumerate(self.operations):
|
||||
self.set_operation_start_end_time(i, d)
|
||||
|
||||
if not d.workstation:
|
||||
continue
|
||||
|
||||
time_log = make_time_log(self.name, d.operation, d.planned_start_time, d.planned_end_time,
|
||||
flt(self.qty) - flt(d.completed_qty), self.project_name, d.workstation, operation_id=d.name)
|
||||
|
||||
if d.workstation:
|
||||
# validate operating hours if workstation [not mandatory] is specified
|
||||
self.check_operation_fits_in_working_hours(d)
|
||||
# validate operating hours if workstation [not mandatory] is specified
|
||||
self.check_operation_fits_in_working_hours(d)
|
||||
|
||||
original_start_time = time_log.from_time
|
||||
while True:
|
||||
@@ -309,10 +312,9 @@ class ProductionOrder(Document):
|
||||
self.actual_end_date = None
|
||||
|
||||
def validate_delivery_date(self):
|
||||
if self.docstatus==1:
|
||||
if self.planned_end_date and self.expected_delivery_date \
|
||||
and getdate(self.expected_delivery_date) < getdate(self.planned_end_date):
|
||||
frappe.msgprint(_("Production might not be able to finish by the Expected Delivery Date."))
|
||||
if self.planned_start_date and self.expected_delivery_date \
|
||||
and getdate(self.expected_delivery_date) < getdate(self.planned_start_date):
|
||||
frappe.throw(_("Expected Delivery Date must be greater than Planned Start Date."))
|
||||
|
||||
def delete_time_logs(self):
|
||||
for time_log in frappe.get_all("Time Log", ["name"], {"production_order": self.name}):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"allow_copy": 1,
|
||||
"creation": "2013-01-21 12:03:47",
|
||||
"default_print_format": "Standard",
|
||||
"docstatus": 0,
|
||||
@@ -154,11 +155,12 @@
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"icon": "icon-calendar",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2015-02-05 05:11:43.010625",
|
||||
"modified": "2015-06-05 11:44:31.629114",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Planning Tool",
|
||||
|
||||
@@ -161,3 +161,13 @@ erpnext.patches.v5_0.set_footer_address
|
||||
execute:frappe.db.set_value("Backup Manager", None, "send_backups_to_dropbox", 1 if frappe.db.get_value("Backup Manager", None, "upload_backups_to_dropbox") in ("Daily", "Weekly") else 0)
|
||||
execute:frappe.db.sql_list("delete from `tabDocPerm` where parent='Issue' and modified_by='Administrator' and role='Guest'")
|
||||
erpnext.patches.v5_0.update_item_and_description_again
|
||||
erpnext.patches.v5_0.repost_gle_for_jv_with_multiple_party
|
||||
erpnext.patches.v5_0.portal_fixes
|
||||
erpnext.patches.v5_0.reset_values_in_tools
|
||||
execute:frappe.delete_doc("Page", "users")
|
||||
erpnext.patches.v5_0.update_material_transferred_for_manufacturing_again
|
||||
erpnext.patches.v5_0.index_on_account_and_gl_entry
|
||||
execute:frappe.db.sql("""delete from `tabProject Task`""")
|
||||
erpnext.patches.v5_0.item_variants
|
||||
erpnext.patches.v5_0.update_item_desc_in_invoice
|
||||
erpnext.patches.v5_1.fix_against_account
|
||||
|
||||
@@ -30,8 +30,8 @@ def create_receivable_payable_account():
|
||||
|
||||
account_id = account.name
|
||||
|
||||
frappe.db.set_value("Company", args["company"], ("default_receivable_account"
|
||||
if args["account_type"]=="Receivable" else "default_payable_account"), account_id)
|
||||
frappe.db.set_value("Company", args["company"], ("default_receivable_account"
|
||||
if args["account_type"]=="Receivable" else "default_payable_account"), account_id)
|
||||
|
||||
receivable_payable_accounts.setdefault(args["company"], {}).setdefault(args["account_type"], account_id)
|
||||
|
||||
|
||||
30
erpnext/patches/v5_0/index_on_account_and_gl_entry.py
Normal file
30
erpnext/patches/v5_0/index_on_account_and_gl_entry.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
index_map = {
|
||||
"Account": ["parent_account", "lft", "rgt"],
|
||||
"GL Entry": ["posting_date", "account", 'party', "voucher_no"],
|
||||
"Sales Invoice": ["posting_date", "debit_to", "customer"],
|
||||
"Purchase Invoice": ["posting_date", "credit_to", "supplier"]
|
||||
}
|
||||
|
||||
for dt, indexes in index_map.items():
|
||||
existing_indexes = [(d.Key_name, d.Column_name) for d in frappe.db.sql("""show index from `tab{0}`
|
||||
where Column_name != 'name'""".format(dt), as_dict=1)]
|
||||
|
||||
for old, column in existing_indexes:
|
||||
if column in ("parent", "group_or_ledger", "is_group", "is_pl_account", "debit_or_credit",
|
||||
"account_name", "company", "project_name", "voucher_date", "due_date", "bill_no",
|
||||
"bill_date", "is_opening", "fiscal_year", "outstanding_amount"):
|
||||
frappe.db.sql("alter table `tab{0}` drop index {1}".format(dt, old))
|
||||
|
||||
existing_indexes = [(d.Key_name, d.Column_name) for d in frappe.db.sql("""show index from `tab{0}`
|
||||
where Column_name != 'name'""".format(dt), as_dict=1)]
|
||||
|
||||
existing_indexed_columns = list(set([x[1] for x in existing_indexes]))
|
||||
|
||||
for new in indexes:
|
||||
if new not in existing_indexed_columns:
|
||||
frappe.db.sql("alter table `tab{0}` add index ({1})".format(dt, new))
|
||||
16
erpnext/patches/v5_0/item_variants.py
Normal file
16
erpnext/patches/v5_0/item_variants.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doctype("Item")
|
||||
for dt in ["manage_variants", "manage_variants_item", "variant_attribute"]:
|
||||
frappe.reload_doc("stock", "doctype", dt)
|
||||
|
||||
for d in frappe.get_list("Item", filters={"has_variants":1}):
|
||||
manage_variant = frappe.new_doc("Manage Variants")
|
||||
manage_variant.item_code = d.name
|
||||
manage_variant.attributes = frappe.db.sql("select item_attribute as attribute, item_attribute_value as attribute_value \
|
||||
from `tabItem Variant` where parent = %s", d.name, as_dict=1)
|
||||
if manage_variant.attributes:
|
||||
manage_variant.generate_combinations()
|
||||
manage_variant.create_variants()
|
||||
frappe.delete_doc("DocType", "Item Variant")
|
||||
6
erpnext/patches/v5_0/portal_fixes.py
Normal file
6
erpnext/patches/v5_0/portal_fixes.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import frappe
|
||||
import erpnext.setup.install
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("website", "doctype", "web_form_field", force=True)
|
||||
erpnext.setup.install.add_web_forms()
|
||||
@@ -0,0 +1,26 @@
|
||||
# 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():
|
||||
je_list = frappe.db.sql_list("""
|
||||
select par.name from `tabJournal Entry` par
|
||||
where par.docstatus=1 and par.creation > '2015-03-01'
|
||||
and (select count(distinct child.party) from `tabJournal Entry Account` child
|
||||
where par.name=child.parent and ifnull(child.party, '') != '') > 1
|
||||
""")
|
||||
|
||||
for d in je_list:
|
||||
# delete existing gle
|
||||
frappe.db.sql("delete from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s", d)
|
||||
|
||||
# repost gl entries
|
||||
je = frappe.get_doc("Journal Entry", d)
|
||||
je.make_gl_entries()
|
||||
|
||||
if je_list:
|
||||
print je_list
|
||||
|
||||
|
||||
11
erpnext/patches/v5_0/reset_values_in_tools.py
Normal file
11
erpnext/patches/v5_0/reset_values_in_tools.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
for dt in ["Payment Tool", "Bank Reconciliation", "Payment Reconciliation", "Leave Control Panel",
|
||||
"Salary Manager", "Upload Attenadance", "Production Planning Tool", "BOM Replace Tool"]:
|
||||
frappe.db.sql("delete from `tabSingles` where doctype=%s", dt)
|
||||
|
||||
@@ -7,6 +7,6 @@ def execute():
|
||||
account_settings = frappe.get_doc("Accounts Settings")
|
||||
|
||||
if not account_settings.frozen_accounts_modifier and account_settings.bde_auth_role:
|
||||
frappe.db.set_value("Account Settings", None,
|
||||
frappe.db.set_value("Accounts Settings", None,
|
||||
"frozen_accounts_modifier", account_settings.bde_auth_role)
|
||||
|
||||
|
||||
50
erpnext/patches/v5_0/update_item_desc_in_invoice.py
Normal file
50
erpnext/patches/v5_0/update_item_desc_in_invoice.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.website.utils import find_first_image
|
||||
from frappe.utils import cstr
|
||||
import re
|
||||
|
||||
def execute():
|
||||
item_details = frappe._dict()
|
||||
for d in frappe.db.sql("select name, description, image from `tabItem`", as_dict=1):
|
||||
description = cstr(d.description).strip()
|
||||
item_details.setdefault(d.name, frappe._dict({
|
||||
"description": description,
|
||||
"image": d.image
|
||||
}))
|
||||
|
||||
|
||||
dt_list= ["Sales Invoice Item","Purchase Invoice Item"]
|
||||
for dt in dt_list:
|
||||
frappe.reload_doctype(dt)
|
||||
records = frappe.db.sql("""select name, item_code, description from `tab{0}`
|
||||
where description is not null """.format(dt), as_dict=1)
|
||||
|
||||
count = 1
|
||||
for d in records:
|
||||
if d.item_code and item_details.get(d.item_code) \
|
||||
and cstr(d.description) == item_details.get(d.item_code).description:
|
||||
desc = item_details.get(d.item_code).description
|
||||
image = item_details.get(d.item_code).image
|
||||
else:
|
||||
desc, image = extract_image_and_description(cstr(d.description))
|
||||
|
||||
if not image:
|
||||
image = item_details.get(d.item_code).image
|
||||
|
||||
frappe.db.sql("""update `tab{0}` set description = %s, image = %s
|
||||
where name = %s """.format(dt), (desc, image, d.name))
|
||||
|
||||
count += 1
|
||||
if count % 500 == 0:
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
def extract_image_and_description(data):
|
||||
image_url = find_first_image(data)
|
||||
desc = data
|
||||
for tag in ("img", "table", "tr", "td"):
|
||||
desc = re.sub("\</*{0}[^>]*\>".format(tag), "", desc)
|
||||
return desc, image_url
|
||||
@@ -0,0 +1,18 @@
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
pro_order_qty_transferred = frappe._dict()
|
||||
for se in frappe.db.sql("""select production_order, sum(fg_completed_qty) as transferred_qty
|
||||
from `tabStock Entry`
|
||||
where docstatus=1 and ifnull(production_order, '') != ''
|
||||
and purpose = 'Material Transfer for Manufacture'
|
||||
group by production_order""", as_dict=1):
|
||||
pro_order_qty_transferred.setdefault(se.production_order, se.transferred_qty)
|
||||
|
||||
for d in frappe.get_all("Production Order", filters={"docstatus": 1}, fields=["name", "qty"]):
|
||||
if d.name in pro_order_qty_transferred:
|
||||
material_transferred_for_manufacturing = pro_order_qty_transferred.get(d.name) \
|
||||
if pro_order_qty_transferred.get(d.name) <= d.qty else d.qty
|
||||
|
||||
frappe.db.sql("""update `tabProduction Order` set material_transferred_for_manufacturing=%s
|
||||
where name=%s""", (material_transferred_for_manufacturing, d.name))
|
||||
0
erpnext/patches/v5_1/__init__.py
Normal file
0
erpnext/patches/v5_1/__init__.py
Normal file
37
erpnext/patches/v5_1/fix_against_account.py
Normal file
37
erpnext/patches/v5_1/fix_against_account.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
from erpnext.accounts.doctype.gl_entry.gl_entry import update_against_account
|
||||
|
||||
def execute():
|
||||
from_date = "2015-05-01"
|
||||
|
||||
for doc in frappe.get_all("Journal Entry",
|
||||
filters={"creation": (">", from_date), "docstatus": "1"}):
|
||||
|
||||
# update in gl_entry
|
||||
update_against_account("Journal Entry", doc.name)
|
||||
|
||||
# update in jv
|
||||
doc = frappe.get_doc("Journal Entry", doc.name)
|
||||
doc.set_against_account()
|
||||
doc.db_update()
|
||||
|
||||
for doc in frappe.get_all("Sales Invoice",
|
||||
filters={"creation": (">", from_date), "docstatus": "1"},
|
||||
fields=["name", "customer"]):
|
||||
|
||||
frappe.db.sql("""update `tabGL Entry` set against=%s
|
||||
where voucher_type='Sales Invoice' and voucher_no=%s
|
||||
and credit > 0 and ifnull(party, '')=''""",
|
||||
(doc.customer, doc.name))
|
||||
|
||||
for doc in frappe.get_all("Purchase Invoice",
|
||||
filters={"creation": (">", from_date), "docstatus": "1"},
|
||||
fields=["name", "supplier"]):
|
||||
|
||||
frappe.db.sql("""update `tabGL Entry` set against=%s
|
||||
where voucher_type='Purchase Invoice' and voucher_no=%s
|
||||
and debit > 0 and ifnull(party, '')=''""",
|
||||
(doc.supplier, doc.name))
|
||||
1
erpnext/projects/doctype/activity_cost/activity_cost.js
Normal file
1
erpnext/projects/doctype/activity_cost/activity_cost.js
Normal file
@@ -0,0 +1 @@
|
||||
cur_frm.add_fetch('employee', 'employee_name', 'employee_name');
|
||||
@@ -2,47 +2,13 @@
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "Activity Cost - .#",
|
||||
"autoname": "AC-.#####",
|
||||
"creation": "2015-03-23 02:00:21.861546",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Employee",
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Employee Name",
|
||||
"options": "employee.employee_name",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "activity_type",
|
||||
@@ -63,6 +29,41 @@
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"label": "Employee",
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"read_only": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Employee Name",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -135,7 +136,7 @@
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2015-04-14 02:08:33.690406",
|
||||
"modified": "2015-06-16 03:12:25.644839",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Activity Cost",
|
||||
|
||||
@@ -15,10 +15,21 @@ class ActivityCost(Document):
|
||||
self.check_unique()
|
||||
|
||||
def set_title(self):
|
||||
self.title = _("{0} for {1}").format(self.employee_name, self.activity_type)
|
||||
|
||||
if self.employee:
|
||||
if not self.employee_name:
|
||||
self.employee_name = frappe.db.get_value("Employee", self.employee, "employee_name")
|
||||
self.title = _("{0} for {1}").format(self.employee_name, self.activity_type)
|
||||
else:
|
||||
self.title = self.activity_type
|
||||
|
||||
def check_unique(self):
|
||||
if frappe.db.sql("""select name from `tabActivity Cost` where employee_name= %s and activity_type= %s and name != %s""",
|
||||
(self.employee_name, self.activity_type, self.name)):
|
||||
frappe.throw(_("Activity Cost exists for Employee {0} against Activity Type - {1}")
|
||||
.format(self.employee, self.activity_type), DuplicationError)
|
||||
if self.employee:
|
||||
if frappe.db.sql("""select name from `tabActivity Cost` where employee_name= %s and activity_type= %s and name != %s""",
|
||||
(self.employee_name, self.activity_type, self.name)):
|
||||
frappe.throw(_("Activity Cost exists for Employee {0} against Activity Type - {1}")
|
||||
.format(self.employee, self.activity_type), DuplicationError)
|
||||
else:
|
||||
if frappe.db.sql("""select name from `tabActivity Cost` where ifnull(employee, '')='' and activity_type= %s and name != %s""",
|
||||
(self.activity_type, self.name)):
|
||||
frappe.throw(_("Default Activity Cost exists for Activity Type - {0}")
|
||||
.format(self.activity_type), DuplicationError)
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 0,
|
||||
"label": "% Tasks Completed",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
@@ -356,7 +357,7 @@
|
||||
"icon": "icon-puzzle-piece",
|
||||
"idx": 1,
|
||||
"max_attachments": 4,
|
||||
"modified": "2015-04-27 07:37:44.239930",
|
||||
"modified": "2015-06-12 09:00:54.080220",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project",
|
||||
|
||||
@@ -15,19 +15,27 @@ class Project(Document):
|
||||
|
||||
def onload(self):
|
||||
"""Load project tasks for quick view"""
|
||||
for task in frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc"):
|
||||
self.append("tasks", {
|
||||
"title": task.subject,
|
||||
"status": task.status,
|
||||
"start_date": task.exp_start_date,
|
||||
"end_date": task.exp_end_date,
|
||||
"description": task.description,
|
||||
"task_id": task.name
|
||||
})
|
||||
|
||||
if not self.get("tasks"):
|
||||
for task in self.get_tasks():
|
||||
self.append("tasks", {
|
||||
"title": task.subject,
|
||||
"status": task.status,
|
||||
"start_date": task.exp_start_date,
|
||||
"end_date": task.exp_end_date,
|
||||
"description": task.description,
|
||||
"task_id": task.name
|
||||
})
|
||||
|
||||
def __setup__(self):
|
||||
self.onload()
|
||||
|
||||
def get_tasks(self):
|
||||
return frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc")
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
self.sync_tasks()
|
||||
self.tasks = []
|
||||
|
||||
def validate_dates(self):
|
||||
if self.expected_start_date and self.expected_end_date:
|
||||
@@ -38,6 +46,8 @@ class Project(Document):
|
||||
"""sync tasks and remove table"""
|
||||
if self.flags.dont_sync_tasks: return
|
||||
|
||||
|
||||
task_added_or_deleted = False
|
||||
task_names = []
|
||||
for t in self.tasks:
|
||||
if t.task_id:
|
||||
@@ -45,6 +55,7 @@ class Project(Document):
|
||||
else:
|
||||
task = frappe.new_doc("Task")
|
||||
task.project = self.name
|
||||
task_added_or_deleted = True
|
||||
|
||||
task.update({
|
||||
"subject": t.title,
|
||||
@@ -62,17 +73,22 @@ class Project(Document):
|
||||
# delete
|
||||
for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
|
||||
frappe.delete_doc("Task", t.name)
|
||||
task_added_or_deleted = True
|
||||
|
||||
if task_added_or_deleted:
|
||||
self.update_project()
|
||||
|
||||
self.tasks = []
|
||||
def update_project(self):
|
||||
self.update_percent_complete()
|
||||
self.update_costing()
|
||||
|
||||
def update_percent_complete(self):
|
||||
total = frappe.db.sql("""select count(*) from tabTask where project=%s""",
|
||||
self.name)[0][0]
|
||||
total = frappe.db.sql("""select count(*) from tabTask where project=%s""", self.name)[0][0]
|
||||
if total:
|
||||
completed = frappe.db.sql("""select count(*) from tabTask where
|
||||
project=%s and status in ('Closed', 'Cancelled')""", self.name)[0][0]
|
||||
frappe.db.set_value("Project", self.name, "percent_complete",
|
||||
int(float(completed) / total * 100))
|
||||
|
||||
self.percent_complete = flt(completed) / total * 100
|
||||
|
||||
def update_costing(self):
|
||||
total_cost = frappe.db.sql("""select sum(total_costing_amount) as costing_amount,
|
||||
|
||||
@@ -5,3 +5,4 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
test_records = frappe.get_test_records('Project')
|
||||
test_ignore = ["Sales Order"]
|
||||
|
||||
@@ -28,7 +28,11 @@ class Task(Document):
|
||||
|
||||
def validate(self):
|
||||
self.validate_dates()
|
||||
|
||||
|
||||
if self.status!=self.get_db_value("status") and self.status == "Closed":
|
||||
from frappe.desk.form.assign_to import clear
|
||||
clear(self.doctype, self.name)
|
||||
|
||||
def validate_dates(self):
|
||||
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
|
||||
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))
|
||||
@@ -39,19 +43,12 @@ class Task(Document):
|
||||
def on_update(self):
|
||||
self.check_recursion()
|
||||
self.reschedule_dependent_tasks()
|
||||
self.update_percentage()
|
||||
self.update_project()
|
||||
|
||||
def update_percentage(self):
|
||||
"""update percent complete in project"""
|
||||
if self.project and not self.flags.from_project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.run_method("update_percent_complete")
|
||||
|
||||
|
||||
def update_total_expense_claim(self):
|
||||
self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
|
||||
self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
|
||||
where project = %s and task = %s and approval_status = "Approved" and docstatus=1""",(self.project, self.name))
|
||||
|
||||
|
||||
def update_time_and_costing(self):
|
||||
tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date,
|
||||
sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
|
||||
@@ -64,14 +61,14 @@ class Task(Document):
|
||||
self.actual_time= tl.time
|
||||
self.act_start_date= tl.start_date
|
||||
self.act_end_date= tl.end_date
|
||||
|
||||
|
||||
def update_project(self):
|
||||
if self.project and frappe.db.exists("Project", self.project):
|
||||
if self.project and not self.flags.from_project:
|
||||
project = frappe.get_doc("Project", self.project)
|
||||
project.flags.dont_sync_tasks = True
|
||||
project.update_costing()
|
||||
project.update_project()
|
||||
project.save()
|
||||
|
||||
|
||||
def check_recursion(self):
|
||||
if self.flags.ignore_recursion_check: return
|
||||
check_list = [['task', 'parent'], ['parent', 'task']]
|
||||
@@ -88,7 +85,7 @@ class Task(Document):
|
||||
task_list.append(b[0])
|
||||
if count == 15:
|
||||
break
|
||||
|
||||
|
||||
def reschedule_dependent_tasks(self):
|
||||
end_date = self.exp_end_date or self.act_end_date
|
||||
if end_date:
|
||||
@@ -137,7 +134,7 @@ def get_project(doctype, txt, searchfield, start, page_len, filters):
|
||||
%(mcond)s
|
||||
order by name
|
||||
limit %(start)s, %(page_len)s """ % {'key': searchfield,
|
||||
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),
|
||||
'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype),
|
||||
'start': start, 'page_len': page_len})
|
||||
|
||||
|
||||
|
||||
@@ -11,19 +11,19 @@ from erpnext.projects.doctype.task.task import CircularReferenceError
|
||||
|
||||
class TestTask(unittest.TestCase):
|
||||
def test_circular_reference(self):
|
||||
|
||||
|
||||
task1 = frappe.new_doc('Task')
|
||||
task1.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-10"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
task2 = frappe.new_doc('Task')
|
||||
task2.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -34,10 +34,10 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task2.save()
|
||||
|
||||
|
||||
task3 = frappe.new_doc('Task')
|
||||
task3.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -53,13 +53,13 @@ class TestTask(unittest.TestCase):
|
||||
"task": task3.name
|
||||
})
|
||||
self.assertRaises(CircularReferenceError, task1.save)
|
||||
|
||||
|
||||
task1.set("depends_on", [])
|
||||
task1.save()
|
||||
|
||||
|
||||
task4 = frappe.new_doc('Task')
|
||||
task4.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -74,20 +74,20 @@ class TestTask(unittest.TestCase):
|
||||
task3.append("depends_on", {
|
||||
"task": task4.name
|
||||
})
|
||||
|
||||
|
||||
def test_reschedule_dependent_task(self):
|
||||
task1 = frappe.new_doc('Task')
|
||||
task1.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 1",
|
||||
"exp_start_date": "2015-1-1",
|
||||
"exp_end_date": "2015-1-10"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
task2 = frappe.new_doc('Task')
|
||||
task2.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 2",
|
||||
"exp_start_date": "2015-1-11",
|
||||
"exp_end_date": "2015-1-15",
|
||||
@@ -98,10 +98,10 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task2.save()
|
||||
|
||||
|
||||
task3 = frappe.new_doc('Task')
|
||||
task3.update({
|
||||
"status": "Open",
|
||||
"status": "Open",
|
||||
"subject": "_Test Task 3",
|
||||
"exp_start_date": "2015-1-16",
|
||||
"exp_end_date": "2015-1-18",
|
||||
@@ -112,18 +112,18 @@ class TestTask(unittest.TestCase):
|
||||
]
|
||||
})
|
||||
task3.save()
|
||||
|
||||
|
||||
task1.update({
|
||||
"exp_end_date": "2015-1-20"
|
||||
})
|
||||
task1.save()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
time_log = frappe.new_doc('Time Log')
|
||||
time_log.update({
|
||||
"from_time": "2015-1-1",
|
||||
@@ -131,18 +131,49 @@ class TestTask(unittest.TestCase):
|
||||
"task": task1.name
|
||||
})
|
||||
time_log.submit()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
time_log.cancel()
|
||||
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
|
||||
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
|
||||
|
||||
|
||||
|
||||
def test_close_assignment(self):
|
||||
task = frappe.new_doc("Task")
|
||||
task.subject = "Test Close Assignment"
|
||||
task.insert()
|
||||
|
||||
def assign():
|
||||
from frappe.desk.form import assign_to
|
||||
assign_to.add({
|
||||
"assign_to": "test@example.com",
|
||||
"doctype": task.doctype,
|
||||
"name": task.name,
|
||||
"description": "Close this task"
|
||||
})
|
||||
|
||||
def get_owner_and_status():
|
||||
return frappe.db.get_value("ToDo", filters={"reference_type": task.doctype, "reference_name": task.name,
|
||||
"description": "Close this task"}, fieldname=("owner", "status"), as_dict=True)
|
||||
|
||||
assign()
|
||||
todo = get_owner_and_status()
|
||||
self.assertEquals(todo.owner, "test@example.com")
|
||||
self.assertEquals(todo.status, "Open")
|
||||
|
||||
# assignment should be
|
||||
task.load_from_db()
|
||||
task.status = "Closed"
|
||||
task.save()
|
||||
todo = get_owner_and_status()
|
||||
self.assertEquals(todo.owner, "test@example.com")
|
||||
self.assertEquals(todo.status, "Closed")
|
||||
|
||||
@@ -128,7 +128,7 @@ class TimeLog(Document):
|
||||
|
||||
def update_production_order(self):
|
||||
"""Updates `start_date`, `end_date`, `status` for operation in Production Order."""
|
||||
|
||||
|
||||
if self.production_order and self.for_manufacturing:
|
||||
if not self.operation_id:
|
||||
frappe.throw(_("Operation ID not set"))
|
||||
@@ -195,8 +195,6 @@ class TimeLog(Document):
|
||||
if self.for_manufacturing:
|
||||
if not self.production_order:
|
||||
frappe.throw(_("Production Order is Mandatory"))
|
||||
if not self.operation:
|
||||
frappe.throw(_("Operation is Mandatory"))
|
||||
if not self.completed_qty:
|
||||
self.completed_qty = 0
|
||||
|
||||
@@ -210,22 +208,23 @@ class TimeLog(Document):
|
||||
self.production_order = None
|
||||
self.operation = None
|
||||
self.quantity = None
|
||||
|
||||
|
||||
def update_cost(self):
|
||||
rate = get_activity_cost(self.employee, self.activity_type)
|
||||
if rate:
|
||||
self.costing_rate = rate.get('costing_rate')
|
||||
self.billing_rate = rate.get('billing_rate')
|
||||
self.billing_rate = rate.get('billing_rate')
|
||||
self.costing_amount = self.costing_rate * self.hours
|
||||
if self.billable:
|
||||
self.billing_amount = self.billing_rate * self.hours
|
||||
else:
|
||||
self.billing_amount = 0
|
||||
|
||||
|
||||
def validate_task(self):
|
||||
if self.project and not self.task:
|
||||
# if a time log is being created against a project without production order
|
||||
if (self.project and not self.production_order) and not self.task:
|
||||
frappe.throw(_("Task is Mandatory if Time Log is against a project"))
|
||||
|
||||
|
||||
def update_task(self):
|
||||
if self.task and frappe.db.exists("Task", self.task):
|
||||
task = frappe.get_doc("Task", self.task)
|
||||
@@ -268,9 +267,12 @@ def get_events(start, end, filters=None):
|
||||
d.title += " for Project: " + d.project
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_activity_cost(employee=None, activity_type=None):
|
||||
rate = frappe.db.sql("""select costing_rate, billing_rate from `tabActivity Cost` where employee= %s
|
||||
and activity_type= %s""", (employee, activity_type), as_dict=1)
|
||||
if not rate:
|
||||
rate = frappe.db.sql("""select costing_rate, billing_rate from `tabActivity Cost` where ifnull(employee, '')=''
|
||||
and activity_type= %s""", (activity_type), as_dict=1)
|
||||
return rate[0] if rate else {}
|
||||
|
||||
@@ -37,6 +37,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
if(this.frm.fields_dict["items"]) {
|
||||
this["items_remove"] = this.calculate_taxes_and_totals;
|
||||
}
|
||||
|
||||
if(this.frm.fields_dict["recurring_print_format"]) {
|
||||
this.frm.set_query("recurring_print_format", function(doc) {
|
||||
return{
|
||||
filters: [
|
||||
['Print Format', 'doc_type', '=', cur_frm.doctype],
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onload_post_render: function() {
|
||||
@@ -105,6 +115,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
},
|
||||
|
||||
barcode: function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.barcode=="" || d.barcode==null) {
|
||||
// barcode cleared, remove item
|
||||
d.item_code = "";
|
||||
}
|
||||
this.item_code(doc, cdt, cdn);
|
||||
},
|
||||
|
||||
item_code: function(doc, cdt, cdn) {
|
||||
var me = this;
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
@@ -773,3 +792,5 @@ frappe.ui.form.on(cur_frm.doctype, "discount_amount", function(frm) {
|
||||
cur_frm.cscript.set_dynamic_labels();
|
||||
cur_frm.cscript.calculate_taxes_and_totals();
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -81,7 +81,8 @@ erpnext.feature_setup.feature_dict = {
|
||||
'Item': {'fields': ['barcode']},
|
||||
'Delivery Note': {'items': ['barcode']},
|
||||
'Sales Invoice': {'items': ['barcode']},
|
||||
'Stock Entry': {'items': ['barcode']}
|
||||
'Stock Entry': {'items': ['barcode']},
|
||||
'Purchase Receipt': {'items': ['barcode']}
|
||||
},
|
||||
'fs_item_group_in_details': {
|
||||
'Delivery Note': {'items':['item_group']},
|
||||
|
||||
@@ -139,7 +139,7 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
|
||||
if(sl.voucher_type=="Stock Reconciliation") {
|
||||
var diff = (sl.qty_after_transaction * sl.valuation_rate) - item.closing_qty_value;
|
||||
wh.fifo_stack.push([sl.qty_after_transaction, sl.valuation_rate, sl.posting_date]);
|
||||
wh.fifo_stack = [[sl.qty_after_transaction, sl.valuation_rate, sl.posting_date]];
|
||||
wh.balance_qty = sl.qty_after_transaction;
|
||||
wh.balance_value = sl.valuation_rate * sl.qty_after_transaction;
|
||||
} else {
|
||||
@@ -167,7 +167,6 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
|
||||
},
|
||||
update_groups: function() {
|
||||
var me = this;
|
||||
|
||||
$.each(this.data, function(i, item) {
|
||||
// update groups
|
||||
if(!item.is_group && me.apply_filter(item, "brand")) {
|
||||
|
||||
@@ -488,7 +488,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -858,7 +858,7 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"max_attachments": 1,
|
||||
"modified": "2015-05-27 02:48:00.388847",
|
||||
"modified": "2015-06-15 15:37:39.199814",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -298,12 +298,13 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "prevdoc_doctype",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Against Doctype",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_doctype",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_width": "150px",
|
||||
@@ -313,11 +314,12 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "prevdoc_docname",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Against Docname",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "prevdoc_docname",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "prevdoc_doctype",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_width": "150px",
|
||||
@@ -390,7 +392,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:15.474119",
|
||||
"modified": "2015-06-02 14:18:00.266748",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation Item",
|
||||
|
||||
@@ -183,5 +183,3 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
cur_frm.email_doc(frappe.boot.notification_settings.sales_order_message);
|
||||
}
|
||||
};
|
||||
|
||||
;
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
{
|
||||
"fieldname": "base_discount_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Discount Amount (Company Currency)",
|
||||
"label": "Additional Discount Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
@@ -1074,13 +1074,22 @@
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.is_recurring==1",
|
||||
"fieldname": "recurring_print_format",
|
||||
"fieldtype": "Link",
|
||||
"label": "Recurring Print Format",
|
||||
"options": "Print Format",
|
||||
"permlevel": 0,
|
||||
"precision": ""
|
||||
}
|
||||
],
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"modified": "2015-05-27 02:48:01.160307",
|
||||
"modified": "2015-06-22 07:29:24.379272",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_filter": 1,
|
||||
"in_list_view": 1,
|
||||
"in_list_view": 0,
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Small Text",
|
||||
@@ -498,7 +498,7 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2015-05-27 02:47:15.134435",
|
||||
"modified": "2015-07-02 05:37:29.289574",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order Item",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user