Compare commits

..

68 Commits

Author SHA1 Message Date
Nabin Hait
baefec4498 Merge branch 'develop' 2015-10-29 16:35:06 +05:30
Nabin Hait
02a56b4e1a bumped to version 6.6.7 2015-10-29 17:05:06 +06:00
Nabin Hait
9a6df0341f Merge pull request #4246 from anandpdoshi/welcome-to-erpnext
Show Welcome to ERPNext after completing Setup Wizard
2015-10-29 16:29:10 +05:30
Nabin Hait
5a90e3b2e9 Merge pull request #4254 from nabinhait/pr_qty
[fix] Consider Rejected Qty for Qty validation in Purchase Receipt
2015-10-29 16:27:02 +05:30
Anand Doshi
7dab3c1f85 Show Welcome to ERPNext after completing Setup Wizard 2015-10-29 15:32:00 +05:30
Nabin Hait
f9a974385a [fix] Consider Rejected Qty for Qty validation in Purchase Receipt 2015-10-29 14:54:29 +05:30
Anand Doshi
32e48bb568 Merge pull request #4250 from anandpdoshi/disable-item
[enhancement] Ability to disable an Item
2015-10-29 13:12:20 +05:30
Anand Doshi
21e09a2bd8 [enhancement] Ability to disable an Item 2015-10-29 12:39:47 +05:30
Nabin Hait
1aa6e98136 Merge pull request #4249 from nabinhait/cc_fix
[fix] Default cost center as per company
2015-10-29 12:28:20 +05:30
Nabin Hait
023c036afa Merge pull request #4248 from anandpdoshi/item-variant-expired
[fix] don't show expired items in website item list. Fixes #4210.
2015-10-29 12:28:03 +05:30
Nabin Hait
8372c44262 [fix] Default cost center as per company 2015-10-29 11:50:36 +05:30
Anand Doshi
6d69ca6bac [fix] don't show expired items in website item list. Fixes #4210. 2015-10-29 11:35:16 +05:30
Nabin Hait
283b55f88c Merge branch 'develop' 2015-10-28 16:07:13 +05:30
Nabin Hait
4757d0634a bumped to version 6.6.6 2015-10-28 16:37:13 +06:00
Nabin Hait
dc8ce7f7e9 Merge pull request #4245 from nabinhait/sr_no
[fix] Serial No query in Warranty Claim
2015-10-28 15:51:32 +05:30
Nabin Hait
d02375e89d Merge branch 'anandpdoshi-file-fix' into develop 2015-10-28 15:50:41 +05:30
Nabin Hait
a90a0528aa Fixed conflict 2015-10-28 15:50:26 +05:30
Nabin Hait
350f9592d3 Merge pull request #4237 from sbkolate/develop
[minor] Update Help Video Links in Buying, CRM, Selling  #4233
2015-10-28 15:44:39 +05:30
Nabin Hait
43e50de6ef Merge pull request #4243 from nabinhait/last_pur_rate
[patch] Deleted Item-wise Last Purchase Rate report
2015-10-28 15:42:35 +05:30
Nabin Hait
a530f410e3 Merge pull request #4242 from nabinhait/to_warehouse_dn
[fix] Ignore users permission for To Warehouse field in Delivery Note
2015-10-28 15:42:16 +05:30
Nabin Hait
bdfb070ed6 [fix] Serial No query in Warranty Claim 2015-10-28 15:38:22 +05:30
Anand Doshi
caa9fc033f [hotfix] vietnamese translation for Debit Note 2015-10-28 14:34:48 +05:30
Nabin Hait
15bf4e5599 [patch] Deleted Item-wise Last Purchase Rate report 2015-10-28 12:48:32 +05:30
Nabin Hait
6d490e530a [fix] Ignore users permission for To Warehouse field in Delivery Note 2015-10-28 12:43:45 +05:30
Rushabh Mehta
9b363fe5f1 Merge pull request #4240 from hubdotcom/patch-1
change to JavaScript
2015-10-28 10:10:23 +05:30
Jamie
3c5df9f64c change to JavaScript 2015-10-27 16:37:45 +00:00
Sambhaji Kolate
fd53991dfa [minor] Update Help Video Links in Buying, CRM, Selling #4233 2015-10-27 17:01:27 +05:30
Anand Doshi
c794ca53fb [fix] delete file records created via item.py even if website_image file didn't exist 2015-10-27 16:56:42 +05:30
Nabin Hait
fa0adafa82 Merge branch 'develop' 2015-10-27 11:29:35 +05:30
Nabin Hait
99f4b43641 bumped to version 6.6.5 2015-10-27 11:59:35 +06:00
Nabin Hait
fdeab29e94 Removed console.log 2015-10-27 11:23:43 +05:30
Nabin Hait
31755b485f Merge pull request #4232 from anandpdoshi/variant-smart-selection
Numeric attribute selector, smart selection of variant based on attribute combinations
2015-10-27 11:22:54 +05:30
Anand Doshi
3f3696d1eb [enhancement] [website] numeric attribute selector, smart selection of variant based on attribute combinations 2015-10-26 21:55:34 +05:30
Nabin Hait
e1a478779c Merge pull request #4231 from nabinhait/pos_fix
[fix] Is POS trigger
2015-10-26 18:22:04 +05:30
Nabin Hait
6c6f3789d0 [fix] Is POS trigger 2015-10-26 18:01:12 +05:30
Nabin Hait
044c43a5cb Merge pull request #4230 from nabinhait/fix26
minor fix
2015-10-26 17:43:17 +05:30
Nabin Hait
9ce9c052e4 Merge pull request #4229 from nabinhait/fix25
[fix] Account Type in Chart of Accounts
2015-10-26 17:43:11 +05:30
Nabin Hait
83e68bb837 minor fix 2015-10-26 17:40:31 +05:30
Nabin Hait
415df04834 [fix] Account Type in Chart of Accounts 2015-10-26 16:43:09 +05:30
Nabin Hait
6d2d6862d6 Merge pull request #4228 from nabinhait/exchange_rate
[fix] account currency is not mandatory in get exchange rate
2015-10-26 15:27:19 +05:30
Nabin Hait
13a65d52dd Merge pull request #4226 from nabinhait/email_digest
[fix] Events in Email Digest
2015-10-26 14:47:09 +05:30
Nabin Hait
6485d4a749 [fix] account currency is not mandatory in get exchange rate 2015-10-26 14:31:17 +05:30
Nabin Hait
2e63c80523 Merge pull request #4220 from nabinhait/fix21
Don't delete tax template and pos profile while deleting company transactions
2015-10-26 14:14:44 +05:30
Nabin Hait
23bd21778e [fix] Events in Email Digest 2015-10-26 14:14:09 +05:30
Nabin Hait
a3f490890d Merge pull request #4227 from nabinhait/dn_to_wh
[fix] Label changed for Target Warehouse in Delivery Note
2015-10-26 13:02:59 +05:30
Nabin Hait
8e3ea32d6d Merge pull request #4222 from nabinhait/tax_rule
Set tax rule based on date
2015-10-26 13:02:21 +05:30
Nabin Hait
c4a1a943ef Merge pull request #4221 from nabinhait/fix22
[fix] Value mapping while making bank entry from Expense Claim
2015-10-26 13:00:52 +05:30
Nabin Hait
abc0b64b68 [fix] Label changed for Target Warehouse in Delivery Note 2015-10-26 11:58:43 +05:30
Nabin Hait
00818bfa90 Set tax rule based on date 2015-10-23 16:26:09 +05:30
Anand Doshi
b9bfe6117e [optimization] Stock Projected Qty report 2015-10-23 14:49:09 +05:30
Nabin Hait
7a9f46d9d1 [fix] Value mapping while making bank entry from Expense Claim 2015-10-23 13:19:01 +05:30
Nabin Hait
a10b52c6e6 Don't delete tax template and pos profile while deleting company transactions 2015-10-23 13:02:55 +05:30
Rushabh Mehta
5033e7b431 [hot] fix stock projected qty 2015-10-23 10:51:56 +05:30
Rushabh Mehta
e6791ee78e [fix] digest values in absolute 2015-10-23 10:39:46 +05:30
Anand Doshi
b84ba868e6 Merge branch 'develop' 2015-10-22 22:02:59 +05:30
Anand Doshi
1c501b6aac bumped to version 6.6.4 2015-10-22 22:32:59 +06:00
Anand Doshi
9a2a6d8fcb [hotfix] setup wizard is_pro_application if not service 2015-10-22 22:02:22 +05:30
Anand Doshi
0b59d1c78b Merge branch 'develop' 2015-10-22 21:59:21 +05:30
Anand Doshi
0fbf10797c bumped to version 6.6.3 2015-10-22 22:29:21 +06:00
Anand Doshi
58344cbb81 [hotfix] setup wizard is_pro_application if not service 2015-10-22 21:57:13 +05:30
Anand Doshi
c6e2c8f79e Merge branch 'develop' 2015-10-22 19:36:09 +05:30
Anand Doshi
b64b461d53 bumped to version 6.6.2 2015-10-22 20:06:09 +06:00
Anand Doshi
0b93bdcf40 [fix] get_party_gle_currency caching 2015-10-22 19:33:08 +05:30
Anand Doshi
e3910d02a5 Merge branch 'develop' 2015-10-22 18:53:19 +05:30
Anand Doshi
0af146cea6 bumped to version 6.6.1 2015-10-22 19:23:19 +06:00
Anand Doshi
683f756d0f [fix] Fetch company of employee in leave application 2015-10-22 18:52:15 +05:30
Anand Doshi
d905204e49 [fix] Update expense account in old purchase invoices if missing 2015-10-22 18:49:08 +05:30
Anand Doshi
d8bc40d7f0 [fix] party gle currency validation 2015-10-22 17:55:22 +05:30
61 changed files with 676 additions and 195 deletions

View File

@@ -6,7 +6,7 @@
Includes: Accounting, Inventory, CRM, Sales, Purchase, Projects, HRMS. Requires MariaDB.
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & Javascript.
ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
- [User Guide](https://manual.erpnext.com)
- [Getting Help](http://erpnext.org/getting-help.html)

View File

@@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = '6.6.0'
__version__ = '6.6.7'

View File

@@ -147,6 +147,8 @@ class Account(Document):
self.validate_warehouse(old_warehouse)
if self.warehouse:
self.validate_warehouse(self.warehouse)
elif self.warehouse:
self.warehouse = None
def validate_warehouse(self, warehouse):
if frappe.db.get_value("Stock Ledger Entry", {"warehouse": warehouse}):

View File

@@ -6,7 +6,7 @@ import frappe
from frappe import _
from frappe.utils import flt, fmt_money, getdate, formatdate
from frappe.model.document import Document
from erpnext.accounts.party import validate_party_gle_currency, get_party_account_currency
from erpnext.accounts.party import validate_party_gle_currency
from erpnext.accounts.utils import get_account_currency
from erpnext.setup.doctype.company.company import get_company_currency
from erpnext.exceptions import InvalidAccountCurrency, CustomerFrozen
@@ -114,13 +114,7 @@ class GLEntry(Document):
.format(self.account, (account_currency or company_currency)), InvalidAccountCurrency)
if self.party_type and self.party:
party_account_currency = get_party_account_currency(self.party_type, self.party, self.company)
if party_account_currency != self.account_currency:
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
.format(self.party_type, self.party, party_account_currency), InvalidAccountCurrency)
validate_party_gle_currency(self.party_type, self.party, self.company)
validate_party_gle_currency(self.party_type, self.party, self.company, self.account_currency)
def validate_balance_type(account, adv_adj=False):
if not adv_adj and account:

View File

@@ -498,14 +498,17 @@ 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", "is_group": 0})
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", "is_group": 0})
account = frappe.db.get_value("Account",
{"company": company, "account_type": "Cash", "is_group": 0})
if account:
account_details = frappe.db.get_value("Account", account, ["account_currency", "account_type"], as_dict=1)
account_details = frappe.db.get_value("Account", account,
["account_currency", "account_type"], as_dict=1)
return {
"account": account,
"balance": get_balance_on(account),
@@ -696,13 +699,15 @@ def get_payment_entry_from_purchase_order(purchase_order):
def get_payment_entry(doc):
bank_account = get_default_bank_cash_account(doc.company, "Bank Entry")
cost_center = frappe.db.get_value("Company", doc.company, "cost_center")
jv = frappe.new_doc('Journal Entry')
jv.voucher_type = 'Bank Entry'
jv.company = doc.company
jv.fiscal_year = doc.fiscal_year
jv.append("accounts")
d1 = jv.append("accounts")
d1.cost_center = cost_center
d2 = jv.append("accounts")
if bank_account:
@@ -712,6 +717,7 @@ def get_payment_entry(doc):
d2.account_type = bank_account["account_type"]
d2.exchange_rate = get_exchange_rate(bank_account["account"],
bank_account["account_currency"], doc.company)
d2.cost_center = cost_center
return jv
@@ -814,11 +820,19 @@ def get_account_balance_and_party_type(account, date, company, debit=None, credi
return grid_values
@frappe.whitelist()
def get_exchange_rate(account, account_currency, company,
def get_exchange_rate(account, account_currency=None, company=None,
reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
from erpnext.setup.utils import get_exchange_rate
account_details = frappe.db.get_value("Account", account,
["account_type", "root_type", "account_currency", "company"], as_dict=1)
if not company:
company = account_details.company
if not account_currency:
account_currency = account_details.account_currency
company_currency = get_company_currency(company)
account_details = frappe.db.get_value("Account", account, ["account_type", "root_type"], as_dict=1)
if account_currency != company_currency:
if reference_type in ("Sales Invoice", "Purchase Invoice") and reference_name:

View File

@@ -160,6 +160,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
me.set_dynamic_labels();
me.calculate_taxes_and_totals();
if(callback_fn) callback_fn();
frappe.after_ajax(function() {
cur_frm.doc.__missing_values_set = false;
})
}
}
});

View File

@@ -109,7 +109,8 @@ def get_party_details(party, party_type, args=None):
def get_tax_template(posting_date, args):
"""Get matching tax rule"""
args = frappe._dict(args)
conditions = []
conditions = ["""(from_date is null or from_date = '' or from_date <= '{0}')
and (to_date is null or to_date = '' or to_date >= '{0}')""".format(posting_date)]
for key, value in args.iteritems():
if key in "use_for_shopping_cart":
@@ -117,16 +118,16 @@ def get_tax_template(posting_date, args):
else:
conditions.append("ifnull({0}, '') in ('', '{1}')".format(key, frappe.db.escape(cstr(value))))
matching = frappe.db.sql("""select * from `tabTax Rule`
tax_rule = frappe.db.sql("""select * from `tabTax Rule`
where {0}""".format(" and ".join(conditions)), as_dict = True)
if not matching:
if not tax_rule:
return None
for rule in matching:
for rule in tax_rule:
rule.no_of_keys_matched = 0
for key in args:
if rule.get(key): rule.no_of_keys_matched += 1
rule = sorted(matching, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
rule = sorted(tax_rule, lambda b, a: cmp(a.no_of_keys_matched, b.no_of_keys_matched) or cmp(a.priority, b.priority))[0]
return rule.sales_tax_template or rule.purchase_tax_template

View File

@@ -209,13 +209,12 @@ erpnext.AccountsChart = Class.extend({
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
options: ['', 'Bank', 'Cash', 'Warehouse', 'Receivable', 'Payable',
'Equity', 'Cost of Goods Sold', 'Fixed Asset', 'Expense Account',
'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'),
description: __("Optional. This setting will be used to filter in various transactions.") },
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"},
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency"}
{fieldtype:'Link', fieldname:'account_currency', label:__('Currency'), options:"Currency",
description: __("Optional. Sets company's default currency, if not specified.")}
]
})

View File

@@ -201,11 +201,14 @@ def get_party_gle_currency(party_type, party, company):
return existing_gle_currency[0][0] if existing_gle_currency else None
return frappe.local_cache("party_gle_currency", (party_type, party, company), generator)
return frappe.local_cache("party_gle_currency", (party_type, party, company), generator,
regenerate_if_none=True)
def validate_party_gle_currency(party_type, party, company):
def validate_party_gle_currency(party_type, party, company, party_account_currency=None):
"""Validate party account currency with existing GL Entry's currency"""
party_account_currency = get_party_account_currency(party_type, party, company)
if not party_account_currency:
party_account_currency = get_party_account_currency(party_type, party, company)
existing_gle_currency = get_party_gle_currency(party_type, party, company)
if existing_gle_currency and party_account_currency != existing_gle_currency:
@@ -221,10 +224,10 @@ def validate_party_accounts(doc):
.format(doc.doctype, doc.name), DuplicatePartyAccountError)
else:
companies.append(account.company)
party_account_currency = frappe.db.get_value("Account", account.account, "account_currency")
existing_gle_currency = get_party_gle_currency(doc.doctype, doc.name, account.company)
if existing_gle_currency and party_account_currency != existing_gle_currency:
frappe.throw(_("Accounting entries have already been made in currency {0} for company {1}. Please select a receivable or payable account with currency {0}.").format(existing_gle_currency, account.company))

View File

@@ -42,6 +42,8 @@ class PurchaseCommon(BuyingController):
items = []
for d in obj.get("items"):
if not d.qty:
if obj.doctype == "Purchase Receipt" and d.rejected_qty:
continue
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
# udpate with latest quantities
@@ -56,11 +58,11 @@ class PurchaseCommon(BuyingController):
d.set(x, f_lst[x])
item = frappe.db.sql("""select is_stock_item, is_purchase_item,
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""",
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
d.item_code, as_dict=1)[0]
from erpnext.stock.doctype.item.item import validate_end_of_life
validate_end_of_life(d.item_code, item.end_of_life)
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
# validate stock item
if item.is_stock_item==1 and d.qty and not d.warehouse:
@@ -72,6 +74,7 @@ class PurchaseCommon(BuyingController):
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
items.append(cstr(d.item_code))
if items and len(items) != len(set(items)) and \
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
frappe.msgprint(_("Warning: Same item has been entered multiple times."))

View File

@@ -164,6 +164,21 @@ def get_data():
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Material Request to Purchase Order"),
"youtube_id": "4TN9kPyfIqM"
},
{
"type": "help",
"label": _("Purchase Order to Payment"),
"youtube_id": "EK65tLdVUDk"
},
{
"type": "help",
"label": _("Managing Subcontracting"),
"youtube_id": "ThiMCC2DtKo"
},
]
},
]

View File

@@ -146,6 +146,11 @@ def get_data():
"label": _("Lead to Quotation"),
"youtube_id": "TxYX4r4JAKA"
},
{
"type": "help",
"label": _("Newsletters"),
"youtube_id": "muLKsCrrDRo"
},
]
},
]

View File

@@ -196,4 +196,30 @@ def get_data():
},
]
},
{
"label": _("Help"),
"icon": "icon-facetime-video",
"items": [
{
"type": "help",
"label": _("Setting up Employees"),
"youtube_id": "USfIUdZlUhw"
},
{
"type": "help",
"label": _("Leave Management"),
"youtube_id": "fc0p_AXebc8"
},
{
"type": "help",
"label": _("Expense Claims"),
"youtube_id": "5SZHJF--ZFY"
},
{
"type": "help",
"label": _("Processing Payroll"),
"youtube_id": "apgE-f25Rm0"
},
]
}
]

View File

@@ -122,6 +122,11 @@ def get_data():
"label": _("Items and Pricing"),
"youtube_id": "qXaEwld4_Ps"
},
{
"type": "help",
"label": _("Item Variants"),
"youtube_id": "OGBETlCzU5o"
},
{
"type": "help",
"label": _("Opening Stock Balance"),

View File

@@ -120,6 +120,16 @@ def get_data():
"label": _("Bill of Materials"),
"youtube_id": "hDV0c1OeWLo"
},
{
"type": "help",
"label": _("Production Planning Tool"),
"youtube_id": "CzatSl4zJ2Y"
},
{
"type": "help",
"label": _("Production Order"),
"youtube_id": "ZotgLyp2YFY"
},
]
}
]

View File

@@ -70,4 +70,15 @@ def get_data():
},
]
},
{
"label": _("Help"),
"icon": "icon-facetime-video",
"items": [
{
"type": "help",
"label": _("Managing Projects"),
"youtube_id": "egxIGwtoKI4"
},
]
},
]

View File

@@ -294,6 +294,16 @@ def get_data():
"label": _("Customer and Supplier"),
"youtube_id": "anoGi_RpQ20"
},
{
"type": "help",
"label": _("Sales Order to Payment"),
"youtube_id": "7AMq4lqkN4A"
},
{
"type": "help",
"label": _("Point-of-Sale"),
"youtube_id": "4WkelWkbP_c"
},
]
},
]

View File

@@ -263,6 +263,11 @@ def get_data():
"label": _("Items and Pricing"),
"youtube_id": "qXaEwld4_Ps"
},
{
"type": "help",
"label": _("Item Variants"),
"youtube_id": "OGBETlCzU5o"
},
{
"type": "help",
"label": _("Opening Stock Balance"),
@@ -270,8 +275,23 @@ def get_data():
},
{
"type": "help",
"label": _("Item Variants"),
"youtube_id": "OGBETlCzU5o"
"label": _("Making Stock Entries"),
"youtube_id": "Njt107hlY3I"
},
{
"type": "help",
"label": _("Serialized Inventory"),
"youtube_id": "gvOVlEwFDAk"
},
{
"type": "help",
"label": _("Batch Inventory"),
"youtube_id": "J0QKl7ABPKM"
},
{
"type": "help",
"label": _("Managing Subcontracting"),
"youtube_id": "ThiMCC2DtKo"
},
]
}

View File

@@ -10,7 +10,7 @@ from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year, get_ac
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document
from erpnext.controllers.sales_and_purchase_return import validate_return
from erpnext.accounts.party import get_party_account_currency, validate_party_gle_currency
from erpnext.accounts.party import get_party_account_currency
from erpnext.exceptions import CustomerFrozen, InvalidCurrency
force_item_fields = ("item_group", "barcode", "brand", "stock_uom")
@@ -435,6 +435,8 @@ class AccountsController(TransactionBase):
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
.format(party_type, party, party_account_currency), InvalidCurrency)
# Note: not validating with gle account because we don't have the account at quotation / sales order level and we shouldn't stop someone from creating a sales invoice if sales order is already created
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, "tax_rate")

View File

@@ -166,6 +166,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
from tabItem
where tabItem.docstatus < 2
and ifnull(tabItem.has_variants, 0)=0
and tabItem.disabled=0
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
and (tabItem.`{key}` LIKE %(txt)s
or tabItem.item_name LIKE %(txt)s
@@ -303,10 +304,10 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
# Hence the first condition is an "OR"
if not filters: filters = {}
condition = ""
condition = ""
if filters.get("company"):
condition += "and tabAccount.company = %(company)s"
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
or tabAccount.account_type in ("Income Account", "Temporary"))
@@ -314,6 +315,6 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.`{key}` LIKE %(txt)s
{condition} {match_condition}"""
.format(condition=condition, match_condition=get_match_cond(doctype), key=searchfield), {
'txt': "%%%s%%" % frappe.db.escape(txt),
'txt': "%%%s%%" % frappe.db.escape(txt),
'company': filters.get("company", "")
})
})

View File

@@ -29,7 +29,7 @@ blogs.
"""
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "6.6.0"
app_version = "6.6.7"
github_link = "https://github.com/frappe/erpnext"
error_report_email = "support@erpnext.com"

View File

@@ -18,24 +18,25 @@ erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
jv.voucher_type = 'Bank Entry';
jv.company = cur_frm.doc.company;
jv.remark = 'Payment against Expense Claim: ' + cur_frm.doc.name;
jv.fiscal_year = cur_frm.doc.fiscal_year;
var expense = cur_frm.doc.expenses || [];
for(var i = 0; i < expense.length; i++){
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
d1.debit = expense[i].sanctioned_amount;
d1.account = expense[i].default_account;
d1.debit_in_account_currency = expense[i].sanctioned_amount;
d1.reference_type = cur_frm.doc.doctype;
d1.reference_name = cur_frm.doc.name;
}
// credit to bank
var d1 = frappe.model.add_child(jv, 'Journal Entry Account', 'accounts');
d1.credit = cur_frm.doc.total_sanctioned_amount;
d1.credit_in_account_currency = cur_frm.doc.total_sanctioned_amount;
d1.reference_type = cur_frm.doc.doctype;
d1.reference_name = cur_frm.doc.name;
if(r.message) {
d1.account = r.message.account;
d1.balance = r.message.balance;
d1.account_currency = r.message.account_currency;
d1.account_type = r.message.account_type;
}
loaddoc('Journal Entry', jv.name);

View File

@@ -2,6 +2,7 @@
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch('employee','employee_name','employee_name');
cur_frm.add_fetch('employee','company','company');
frappe.ui.form.on("Leave Application", {
onload: function(frm) {

View File

@@ -140,7 +140,7 @@ erpnext.production_order = {
} else msgprint(__("Please enter Production Item first"));
});
},
set_default_warehouse: function(frm) {
frappe.call({
method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse",

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, get_datetime, getdate, date_diff, cint
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
from frappe import _
from frappe.model.document import Document
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
@@ -159,22 +159,22 @@ class ProductionOrder(Document):
def on_cancel(self):
self.validate_cancel()
frappe.db.set(self,'status', 'Cancelled')
self.update_planned_qty()
self.delete_time_logs()
def validate_cancel(self):
if self.status == "Stopped":
frappe.throw(_("Stopped Production Order cannot be cancelled, Unstop it first to cancel"))
# Check whether any stock entry exists against this Production Order
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.name)
if stock_entry:
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
def update_planned_qty(self):
def update_planned_qty(self):
update_bin_qty(self.production_item, self.fg_warehouse, {
"planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)
})
@@ -342,8 +342,8 @@ class ProductionOrder(Document):
@frappe.whitelist()
def get_item_details(item):
res = frappe.db.sql("""select stock_uom, description
from `tabItem` where (ifnull(end_of_life, "0000-00-00")="0000-00-00" or end_of_life > now())
and name=%s""", item, as_dict=1)
from `tabItem` where disabled=0 and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)
and name=%s""", (nowdate(), item), as_dict=1)
if not res:
return {}

View File

@@ -86,7 +86,7 @@ class TestProductionOrder(unittest.TestCase):
self.assertEqual(prod_order.name, time_log.production_order)
self.assertEqual((prod_order.qty - d.completed_qty), time_log.completed_qty)
self.assertEqual(time_diff_in_hours(d.planned_end_time, d.planned_start_time),time_log.hours)
manufacturing_settings = frappe.get_doc({
"doctype": "Manufacturing Settings",
"allow_production_on_holidays": 0
@@ -136,6 +136,11 @@ class TestProductionOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, prod_order.save)
frappe.db.set_value("Item", "_Test FG Item", "end_of_life", None)
frappe.db.set_value("Item", "_Test FG Item", "disabled", 1)
self.assertRaises(frappe.ValidationError, prod_order.save)
frappe.db.set_value("Item", "_Test FG Item", "disabled", 0)
prod_order = make_prod_order_test_record(item="_Test Variant Item", qty=1, do_not_save=True)
self.assertRaises(ItemHasVariantError, prod_order.save)

View File

@@ -228,3 +228,5 @@ erpnext.patches.v6_4.set_user_in_contact
erpnext.patches.v6_4.make_image_thumbnail #2015-10-20
erpnext.patches.v6_5.show_in_website_for_template_item
erpnext.patches.v6_4.fix_expense_included_in_valuation
execute:frappe.delete_doc_if_exists("Report", "Item-wise Last Purchase Rate")
erpnext.patches.v6_6.fix_website_image

View File

@@ -8,13 +8,13 @@ from frappe.utils import cstr
def execute():
for company in frappe.db.sql("select name, expenses_included_in_valuation from tabCompany", as_dict=1):
frozen_date = get_frozen_date(company.name, company.expenses_included_in_valuation)
# Purchase Invoices after frozen date
# Purchase Invoices after frozen date
# which are not against Receipt, but valuation related tax is there
pi_list = frappe.db.sql("""
select distinct pi.name
from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` pi_item
where
where
pi.name = pi_item.parent
and pi.company = %s
and pi.posting_date > %s
@@ -25,40 +25,50 @@ def execute():
and (pi_item.item_code is not null and pi_item.item_code != '')
and exists(select name from `tabItem` where name=pi_item.item_code and is_stock_item=1)
""", (company.name, frozen_date), as_dict=1)
for pi in pi_list:
# Check whether gle exists for Expenses Included in Valuation account against the PI
gle_for_expenses_included_in_valuation = frappe.db.sql("""select name from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s and account=%s""",
gle_for_expenses_included_in_valuation = frappe.db.sql("""select name from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s and account=%s""",
(pi.name, company.expenses_included_in_valuation))
if gle_for_expenses_included_in_valuation:
print pi.name
frappe.db.sql("""delete from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no=%s""", pi.name)
purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name)
# some old entries have missing expense accounts
if purchase_invoice.against_expense_account:
expense_account = purchase_invoice.against_expense_account.split(",")
if len(expense_account) == 1:
expense_account = expense_account[0]
for item in purchase_invoice.items:
if not item.expense_account:
item.db_set("expense_account", expense_account, update_modified=False)
purchase_invoice.make_gl_entries()
print pi.name
def get_frozen_date(company, account):
# Accounting frozen upto
accounts_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto")
# Last adjustment entry to correct Expenses Included in Valuation account balance
last_adjustment_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
last_adjustment_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
where account=%s and company=%s and voucher_type = 'Journal Entry'
order by posting_date desc limit 1""", (account, company))
last_adjustment_date = cstr(last_adjustment_entry[0][0]) if last_adjustment_entry else None
# Last period closing voucher
last_closing_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
last_closing_entry = frappe.db.sql("""select posting_date from `tabGL Entry`
where company=%s and voucher_type = 'Period Closing Voucher'
order by posting_date desc limit 1""", company)
last_closing_date = cstr(last_closing_entry[0][0]) if last_closing_entry else None
frozen_date = max([accounts_frozen_upto, last_adjustment_date, last_closing_date])
return frozen_date or '1900-01-01'
return frozen_date or '1900-01-01'

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,32 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import encode
def execute():
"""Fix the File records created via item.py even if the website_image file didn't exist"""
for item in frappe.db.sql_list("""select name from `tabItem`
where website_image is not null and website_image != ''
and website_image like '/files/%'
and exists (
select name from `tabFile`
where attached_to_doctype='Item'
and attached_to_name=`tabItem`.name
and file_url=`tabItem`.website_image
and (file_name is null or file_name = '')
)"""):
item = frappe.get_doc("Item", item)
file = frappe.get_doc("File", {
"attached_to_doctype": "Item",
"attached_to_name": item.name,
"file_url": item.website_image
})
try:
file.validate_file()
except IOError:
print encode(item.website_image), "does not exist"
file.delete()
item.db_set("website_image", None, update_modified=False)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 KiB

View File

@@ -76,10 +76,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
if(this.frm.doc.__islocal && !(this.frm.doc.taxes || []).length
&& !(this.frm.doc.__onload ? this.frm.doc.__onload.load_after_mapping : false)) {
this.apply_default_taxes();
}
if(this.frm.doc.__islocal && this.frm.doc.company && this.frm.doc["items"] && !this.frm.doc.is_pos) {
this.calculate_taxes_and_totals();
} else if(this.frm.doc.__islocal && this.frm.doc.company && this.frm.doc["items"]
&& !this.frm.doc.is_pos) {
me.calculate_taxes_and_totals();
}
if(frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "item_code")) {
cur_frm.get_field("items").grid.set_multiple_add("item_code", "qty");
@@ -102,7 +101,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.frm.doc.name);
if(taxes_and_charges_field) {
frappe.call({
return frappe.call({
method: "erpnext.controllers.accounts_controller.get_default_taxes_and_charges",
args: {
"master_doctype": taxes_and_charges_field.options
@@ -110,6 +109,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
callback: function(r) {
if(!r.exc) {
me.frm.set_value("taxes", r.message);
me.calculate_taxes_and_totals();
}
}
});
@@ -362,7 +362,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
},
get_exchange_rate: function(from_currency, to_currency, callback) {
frappe.call({
return frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
from_currency: from_currency,

View File

@@ -22,11 +22,16 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) {
}
if (args) {
args.posting_date = frm.doc.transaction_date;
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
}
}
if(!args) return;
if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date",
args.posting_date, args.party_type=="Customer" ? "customer": "supplier")) return;
}
args.currency = frm.doc.currency;
args.company = frm.doc.company;
args.doctype = frm.doc.doctype;
@@ -64,6 +69,15 @@ erpnext.utils.get_address_display = function(frm, address_field, display_field)
if(r.message){
frm.set_value(display_field, r.message)
}
if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) {
if(!erpnext.utils.validate_mandatory(frm, "Customer/Supplier",
frm.doc.customer || frm.doc.supplier, address_field)) return;
if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date",
frm.doc.posting_date || frm.doc.transaction_date, address_field)) return;
} else return;
frappe.call({
method: "erpnext.accounts.party.set_taxes",
args: {
@@ -99,3 +113,13 @@ erpnext.utils.get_contact_details = function(frm) {
})
}
}
erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) {
if(!value) {
frm.doc[trigger_on] = "";
refresh_field(trigger_on);
frappe.msgprint(__("Please enter {0} first", [label]));
return false;
}
return true;
}

View File

@@ -22,8 +22,10 @@ def delete_company_transactions(company_name):
for doctype in frappe.db.sql_list("""select parent from
tabDocField where fieldtype='Link' and options='Company'"""):
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail", "Party Account", "Employee"):
delete_for_doctype(doctype, company_name)
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail",
"Party Account", "Employee", "Sales Taxes and Charges Template",
"Purchase Taxes and Charges Template", "POS Profile"):
delete_for_doctype(doctype, company_name)
# Clear notification counts
clear_notifications()

View File

@@ -139,7 +139,7 @@ class EmailDigest(Document):
for i, e in enumerate(events):
e.starts_on_label = format_time(e.starts_on)
e.ends_on_label = format_time(e.ends_on)
e.ends_on_label = format_time(e.ends_on) if e.ends_on else None
e.date = formatdate(e.starts)
e.link = get_url_to_form("Event", e.name)
@@ -346,7 +346,7 @@ class EmailDigest(Document):
self.get_next_sending()
def fmt_money(self, value):
return fmt_money(value, currency = self.currency)
return fmt_money(abs(value), currency = self.currency)
def send():
now_date = now_datetime().date()

View File

@@ -52,6 +52,8 @@
<span style="{{ label_css }}">
{% if e.all_day %}
{{ _("All Day") }}
{% elif (not e.ends_on_label or e.starts_on_label == e.ends_on_label)%}
{{ e.starts_on_label }}
{% else %}
{{ e.starts_on_label }} - {{ e.ends_on_label }}
{% endif %}

View File

@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
import urllib
from frappe.utils import nowdate
from frappe.utils.nestedset import NestedSet
from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache
@@ -71,14 +72,16 @@ def get_product_list_for_group(product_group=None, start=0, limit=10):
concat(parent_website_route, "/", page_name) as route
from `tabItem`
where show_in_website = 1
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and (variant_of = '' or variant_of is null)
and (item_group in (%s)
or name in (select parent from `tabWebsite Item Group` where item_group in (%s)))
""" % (child_groups, child_groups)
and (item_group in ({child_groups})
or name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups})))
""".format(child_groups=child_groups)
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1)
data = frappe.db.sql(query, {"product_group": product_group, "today": nowdate()}, as_dict=1)
return [get_item_for_list_in_html(r) for r in data]

View File

@@ -658,7 +658,7 @@ $.extend(erpnext.wiz, {
return frappe.render_template("setup_wizard_message", {
image: "/assets/frappe/images/ui/bubble-tea-happy.svg",
title: __('Setup Complete'),
message: __('Your setup is complete. Refreshing.') + ".."
message: ""
});
},
@@ -670,6 +670,7 @@ $.extend(erpnext.wiz, {
args: values,
callback: function(r) {
wiz.show_complete();
localStorage.setItem("session_last_route", "#welcome-to-erpnext");
setTimeout(function() {
window.location = "/desk";
}, 2000);

View File

@@ -374,6 +374,7 @@ def create_items(args):
is_sales_item = args.get("is_sales_item_" + str(i))
is_purchase_item = args.get("is_purchase_item_" + str(i))
is_stock_item = item_group!=_("Services")
is_pro_applicable = item_group!=_("Services")
default_warehouse = ""
if is_stock_item:
default_warehouse = frappe.db.get_value("Warehouse", filters={
@@ -391,6 +392,7 @@ def create_items(args):
"is_purchase_item": 1 if is_purchase_item else 0,
"show_in_website": 1,
"is_stock_item": is_stock_item and 1 or 0,
"is_pro_applicable": is_pro_applicable and 1 or 0,
"item_group": item_group,
"stock_uom": args.get("item_uom_" + str(i)),
"default_warehouse": default_warehouse

View File

@@ -0,0 +1,13 @@
#page-welcome-to-erpnext ul li {
margin: 7px 0px;
}
#page-welcome-to-erpnext .video-placeholder-image {
width: 100%;
cursor: pointer;
}
#page-welcome-to-erpnext .youtube-icon {
width: 10%;
cursor: pointer;
}

View File

@@ -0,0 +1,31 @@
<div class="container welcome-to-erpnext text-center" style="padding: 30px 0px;">
<div class="row">
<div class="col-md-8 col-md-push-2 col-sm-12">
<h1>{%= __("Welcome to ERPNext") %}</h1>
<p class="text-muted">
{%= __("To get the best out of ERPNext, we recommend that you take some time and watch these help videos.") %}
<br><br>
</p>
<div class="embed-responsive embed-responsive-16by9">
<div class="video-placeholder embed-responsive-item">
<img class="video-placeholder-image"
src="/assets/erpnext/images/erpnext-video-placeholder.jpg">
<img class="centered youtube-icon"
src="/assets/erpnext/images/YouTube-icon-full_color.png">
</div>
</div>
<br>
<hr>
<h3>Next Steps</h3>
<ul class="list-unstyled">
<li><a class="text-muted" href="#">{%= __("Go to the Desktop and start using ERPNext") %}</a></li>
<li><a class="text-muted" href="#Module/Learn">{%= __("View a list of all the help videos") %}</a></li>
<li><a class="text-muted" href="https://manual.erpnext.com" target="_blank">{%= __("Read the ERPNext Manual") %}</a></li>
<li><a class="text-muted" href="https://discuss.erpnext.com" target="_blank">{%= __("Community Forum") %}</a></li>
</ul>
</div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
frappe.pages['welcome-to-erpnext'].on_page_load = function(wrapper) {
var parent = $('<div class="welcome-to-erpnext"></div>').appendTo(wrapper);
parent.html(frappe.render_template("welcome_to_erpnext", {}));
parent.find(".video-placeholder").on("click", function() {
parent.find(".video-placeholder").addClass("hidden");
parent.find(".embed-responsive").append('<iframe class="embed-responsive-item video-playlist" src="https://www.youtube.com/embed/videoseries?list=PL3lFfCEoMxvxDHtYyQFJeUYkWzQpXwFM9&color=white&autoplay=1" allowfullscreen></iframe>')
});
}

View File

@@ -0,0 +1,17 @@
{
"content": null,
"creation": "2015-10-28 16:27:02.197707",
"docstatus": 0,
"doctype": "Page",
"modified": "2015-10-28 16:27:02.197707",
"modified_by": "Administrator",
"module": "Setup",
"name": "welcome-to-erpnext",
"owner": "Administrator",
"page_name": "welcome-to-erpnext",
"roles": [],
"script": null,
"standard": "Yes",
"style": null,
"title": "Welcome to ERPNext"
}

View File

@@ -735,7 +735,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Warehouse",
"label": "From Warehouse",
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
@@ -755,13 +755,15 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "",
"description": "",
"fieldname": "target_warehouse",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_user_permissions": 1,
"in_filter": 0,
"in_list_view": 0,
"label": "Target Warehouse",
"label": "To Warehouse (Optional)",
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
@@ -831,7 +833,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Available Qty at Warehouse",
"label": "Available Qty at From Warehouse",
"no_copy": 1,
"oldfieldname": "actual_qty",
"oldfieldtype": "Currency",
@@ -857,7 +859,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Available Batch Qty at Warehouse",
"label": "Available Batch Qty at From Warehouse",
"no_copy": 1,
"permlevel": 0,
"precision": "",
@@ -1160,7 +1162,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2015-10-19 03:04:50.887288",
"modified": "2015-10-28 12:41:53.738462",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note Item",

View File

@@ -178,31 +178,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "2099-12-31",
"depends_on": "is_stock_item",
"fieldname": "end_of_life",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "End of Life",
"no_copy": 0,
"oldfieldname": "end_of_life",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -249,6 +224,28 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Disabled",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -436,6 +433,31 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "2099-12-31",
"depends_on": "is_stock_item",
"fieldname": "end_of_life",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "End of Life",
"no_copy": 0,
"oldfieldname": "end_of_life",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@@ -2113,7 +2135,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2015-10-20 12:14:43.315827",
"modified": "2015-10-29 02:25:26.256373",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
import json
import urllib
import itertools
from frappe import msgprint, _
from frappe.utils import cstr, flt, cint, getdate, now_datetime, formatdate
from frappe.website.website_generator import WebsiteGenerator
@@ -103,12 +104,16 @@ class Item(WebsiteGenerator):
# for CSV import
if not file_doc:
file_doc = frappe.get_doc({
"doctype": "File",
"file_url": self.website_image,
"attached_to_doctype": "Item",
"attached_to_name": self.name
}).insert()
try:
file_doc = frappe.get_doc({
"doctype": "File",
"file_url": self.website_image,
"attached_to_doctype": "Item",
"attached_to_name": self.name
}).insert()
except IOError:
self.website_image = None
if file_doc:
if not file_doc.thumbnail_url:
@@ -130,6 +135,8 @@ class Item(WebsiteGenerator):
self.set_attribute_context(context)
self.set_disabled_attributes(context)
context.parents = self.get_parents(context)
return context
@@ -189,15 +196,63 @@ class Item(WebsiteGenerator):
for attr in self.attributes:
values = context.attribute_values.setdefault(attr.attribute, [])
# get list of values defined (for sequence)
for attr_value in frappe.db.get_all("Item Attribute Value",
fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"):
if cint(frappe.db.get_value("Item Attribute", attr.attribute, "numeric_values")):
for val in sorted(attribute_values_available.get(attr.attribute, []), key=flt):
values.append(val)
if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
values.append(attr_value.attribute_value)
else:
# get list of values defined (for sequence)
for attr_value in frappe.db.get_all("Item Attribute Value",
fields=["attribute_value"], filters={"parent": attr.attribute}, order_by="idx asc"):
if attr_value.attribute_value in attribute_values_available.get(attr.attribute, []):
values.append(attr_value.attribute_value)
context.variant_info = json.dumps(context.variants)
def set_disabled_attributes(self, context):
"""Disable selection options of attribute combinations that do not result in a variant"""
if not self.attributes:
return
context.disabled_attributes = {}
attributes = [attr.attribute for attr in self.attributes]
def find_variant(combination):
for variant in context.variants:
if len(variant.attributes) < len(attributes):
continue
if "combination" not in variant:
ref_combination = []
for attr in variant.attributes:
idx = attributes.index(attr.attribute)
ref_combination.insert(idx, attr.attribute_value)
variant["combination"] = ref_combination
if not (set(combination) - set(variant["combination"])):
# check if the combination is a subset of a variant combination
# eg. [Blue, 0.5] is a possible combination if exists [Blue, Large, 0.5]
return True
for i, attr in enumerate(self.attributes):
if i==0:
continue
combination_source = []
# loop through previous attributes
for prev_attr in self.attributes[:i]:
combination_source.append([context.selected_attributes.get(prev_attr.attribute)])
combination_source.append(context.attribute_values[attr.attribute])
for combination in itertools.product(*combination_source):
if not find_variant(combination):
context.disabled_attributes.setdefault(attr.attribute, []).append(combination[-1])
def check_warehouse_is_set_for_stock_item(self):
if self.is_stock_item==1 and not self.default_warehouse and frappe.get_all("Warehouse"):
frappe.msgprint(_("Default Warehouse is mandatory for stock Item."),
@@ -469,14 +524,17 @@ class Item(WebsiteGenerator):
if variant and self.get("__islocal"):
frappe.throw(_("Item variant {0} exists with same attributes").format(variant), ItemVariantExistsError)
def validate_end_of_life(item_code, end_of_life=None, verbose=1):
if not end_of_life:
end_of_life = frappe.db.get_value("Item", item_code, "end_of_life")
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
if (not end_of_life) or (disabled is None):
end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"])
if end_of_life and end_of_life!="0000-00-00" and getdate(end_of_life) <= now_datetime().date():
msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life))
_msgprint(msg, verbose)
if disabled:
_msgprint(_("Item {0} is disabled").format(item_code), verbose)
def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
if not is_stock_item:
is_stock_item = frappe.db.get_value("Item", item_code, "is_stock_item")

View File

@@ -1,16 +1,18 @@
frappe.listview_settings['Item'] = {
add_fields: ["item_name", "stock_uom", "item_group", "image", "variant_of",
"has_variants", "end_of_life", "is_sales_item"],
"has_variants", "end_of_life", "disabled", "is_sales_item"],
get_indicator: function(doc) {
if(doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) {
return [__("Expired"), "grey", "end_of_life,<,Today"]
} else if(doc.has_variants) {
return [__("Template"), "blue", "has_variants,=,Yes"]
} else if(doc.variant_of) {
return [__("Variant"), "green", "variant_of,=," + doc.variant_of]
if (doc.disabled) {
return [__("Disabled"), "grey", "disabled,=,Yes"];
} else if (doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) {
return [__("Expired"), "grey", "end_of_life,<,Today"];
} else if (doc.has_variants) {
return [__("Template"), "blue", "has_variants,=,Yes"];
} else if (doc.variant_of) {
return [__("Variant"), "green", "variant_of,=," + doc.variant_of];
} else {
return [__("Active"), "blue", "end_of_life,>=,Today"]
return [__("Active"), "blue", "end_of_life,>=,Today"];
}
}
};

View File

@@ -155,7 +155,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Warehouse",
"label": "From Warehouse",
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
@@ -179,7 +179,7 @@
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Target Warehouse",
"label": "To Warehouse (Optional)",
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
@@ -511,7 +511,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2015-10-12 07:38:58.896987",
"modified": "2015-10-26 02:25:47.718911",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe import _
from frappe.utils import cstr, cint, flt, comma_or, getdate
from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError
from erpnext.stock.get_item_details import get_available_qty, get_default_cost_center, get_conversion_factor
@@ -359,7 +359,7 @@ class StockEntry(StockController):
def update_stock_ledger(self):
sl_entries = []
# make sl entries for source warehouse first, then do for target warehouse
for d in self.get('items'):
if cstr(d.s_warehouse):
@@ -368,7 +368,7 @@ class StockEntry(StockController):
"actual_qty": -flt(d.transfer_qty),
"incoming_rate": 0
}))
for d in self.get('items'):
if cstr(d.t_warehouse):
sl_entries.append(self.get_sl_entries(d, {
@@ -438,8 +438,10 @@ class StockEntry(StockController):
def get_item_details(self, args=None, for_update=False):
item = frappe.db.sql("""select stock_uom, description, image, item_name,
expense_account, buying_cost_center, item_group from `tabItem`
where name = %s and (ifnull(end_of_life,'0000-00-00')='0000-00-00' or end_of_life > now())""",
(args.get('item_code')), as_dict = 1)
where name = %s
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""",
(args.get('item_code'), nowdate()), as_dict = 1)
if not item:
frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code")))

View File

@@ -130,7 +130,7 @@ class StockReconciliation(StockController):
item = frappe.get_doc("Item", item_code)
# end of life and stock item
validate_end_of_life(item_code, item.end_of_life, verbose=0)
validate_end_of_life(item_code, item.end_of_life, item.disabled, verbose=0)
validate_is_stock_item(item_code, item.is_stock_item, verbose=0)
# item should not be serialized

View File

@@ -113,7 +113,7 @@ def validate_item_details(args, item):
throw(_("Please specify Company"))
from erpnext.stock.doctype.item.item import validate_end_of_life
validate_end_of_life(item.name, item.end_of_life)
validate_end_of_life(item.name, item.end_of_life, item.disabled)
if args.transaction_type == "selling":
# validate if sales item or service item

View File

@@ -23,6 +23,7 @@ def _reorder_item():
items_to_consider = frappe.db.sql_list("""select name from `tabItem` item
where is_stock_item=1 and has_variants=0
and (is_purchase_item=1 or is_sub_contracted_item=1)
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and ((re_order_level is not null and re_order_level > 0)
or exists (select name from `tabItem Reorder` ir where ir.parent=item.name)

View File

@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt, today
def execute(filters=None):
filters = frappe._dict(filters or {})
@@ -18,12 +19,19 @@ def get_columns():
_("Shortage Qty") + ":Float:100"]
def get_data(filters):
item_map = {}
bin_list = get_bin_list(filters)
item_map = get_item_map(filters.get("item_code"))
warehouse_company = {}
data = []
for bin in get_bin_list(filters):
item = item_map.setdefault(bin.item_code, frappe.get_doc("Item", bin.item_code))
for bin in bin_list:
item = item_map.get(bin.item_code)
if not item:
# likely an item that has reached its end of life
continue
# item = item_map.setdefault(bin.item_code, get_item(bin.item_code))
company = warehouse_company.setdefault(bin.warehouse, frappe.db.get_value("Warehouse", bin.warehouse, "company"))
if filters.brand and filters.brand != item.brand:
@@ -45,7 +53,7 @@ def get_data(filters):
data.append([item.name, item.item_name, item.description, item.item_group, item.brand, bin.warehouse,
item.stock_uom, bin.actual_qty, bin.planned_qty, bin.indented_qty, bin.ordered_qty, bin.reserved_qty,
bin.projected_qty, re_order_level, re_order_qty, re_order_level - bin.projected_qty])
bin.projected_qty, re_order_level, re_order_qty, re_order_level - flt(bin.projected_qty)])
return data
@@ -61,3 +69,36 @@ def get_bin_list(filters):
filters=bin_filters, order_by="item_code, warehouse")
return bin_list
def get_item_map(item_code):
"""Optimization: get only the item doc and re_order_levels table"""
condition = ""
if item_code:
condition = 'and item_code = "{0}"'.format(frappe.db.escape(item_code))
items = frappe.db.sql("""select * from `tabItem` item
where is_stock_item = 1
and disabled=0
{condition}
and (end_of_life > %(today)s or end_of_life is null or end_of_life='0000-00-00')
and exists (select name from `tabBin` bin where bin.item_code=item.name)"""\
.format(condition=condition), {"today": today()}, as_dict=True)
condition = ""
if item_code:
condition = 'where parent="{0}"'.format(frappe.db.escape(item_code))
reorder_levels = frappe._dict()
for ir in frappe.db.sql("""select * from `tabItem Reorder` {condition}""".format(condition=condition), as_dict=1):
if ir.parent not in reorder_levels:
reorder_levels[ir.parent] = []
reorder_levels[ir.parent].append(ir)
item_map = frappe._dict()
for item in items:
item["reorder_levels"] = reorder_levels.get(item.name) or []
item_map[item.name] = item
return item_map

View File

@@ -51,7 +51,7 @@ cur_frm.fields_dict['serial_no'].get_query = function(doc, cdt, cdn) {
var cond = [];
var filter = [
['Serial No', 'docstatus', '!=', 2],
['Serial No', 'status', '=', "Delivered"]
['Serial No', 'warehouse', '=', ""]
];
if(doc.item_code) {
cond = ['Serial No', 'item_code', '=', doc.item_code];

View File

@@ -24,12 +24,13 @@
{{ web_long_description or description or _("No description given") }}
</div>
<p class="text-muted">
{{ _("Item Code") }}: <span itemprop="productID">{{ name }}</span></p>
{{ _("Item Code") }}: <span itemprop="productID">{{ variant and variant.name or name }}</span></p>
<br>
<div class="item-attribute-selectors">
{% if has_variants %}
{% for d in attributes %}
<div class="item-view-attribute"
{% if attribute_values[d.attribute] -%}
<div class="item-view-attribute {% if (attribute_values[d.attribute] | len)==1 -%} hidden {%- endif %}"
style="margin-bottom: 10px;">
<h6 class="text-muted">{{ _(d.attribute) }}</h6>
<select class="form-control"
@@ -37,12 +38,17 @@
data-attribute="{{ d.attribute }}">
{% for value in attribute_values[d.attribute] %}
<option value="{{ value }}"
{% if selected_attributes and selected_attributes[d.attribute]==value -%} selected {%- endif %}>
{% if selected_attributes and selected_attributes[d.attribute]==value -%}
selected
{%- elif disabled_attributes and value in disabled_attributes.get(d.attribute, []) -%}
disabled
{%- endif %}>
{{ _(value) }}
</option>
{% endfor %}
</select>
</div>
{%- endif %}
{% endfor %}
{% endif %}
</div>

View File

@@ -64,8 +64,23 @@ frappe.ready(function() {
});
});
$("[itemscope] .item-view-attribute select").on("change", function() {
var item_code = encodeURIComponent(get_item_code());
$("[itemscope] .item-view-attribute .form-control").on("change", function() {
try {
var item_code = encodeURIComponent(get_item_code());
} catch(e) {
// unable to find variant
// then chose the closest available one
var attribute = $(this).attr("data-attribute");
var attribute_value = $(this).val()
var item_code = update_attribute_selectors(attribute, attribute_value);
if (!item_code) {
msgprint(__("Please select some other value for {0}", [attribute]))
throw e;
}
}
if (window.location.search.indexOf(item_code)!==-1) {
return;
}
@@ -83,10 +98,8 @@ var toggle_update_cart = function(qty) {
function get_item_code() {
if(window.variant_info) {
attributes = {};
$('[itemscope]').find(".item-view-attribute select").each(function() {
attributes[$(this).attr('data-attribute')] = $(this).val();
});
var attributes = get_selected_attributes();
for(var i in variant_info) {
var variant = variant_info[i];
var match = true;
@@ -106,3 +119,51 @@ function get_item_code() {
return item_code;
}
}
function update_attribute_selectors(selected_attribute, selected_attribute_value) {
// find the closest match keeping the selected attribute in focus and get the item code
var attributes = get_selected_attributes();
var previous_match_score = 0;
var matched;
for(var i in variant_info) {
var variant = variant_info[i];
var match_score = 0;
var has_selected_attribute = false;
for(var j in variant.attributes) {
if(attributes[variant.attributes[j].attribute]===variant.attributes[j].attribute_value) {
match_score = match_score + 1;
if (variant.attributes[j].attribute==selected_attribute && variant.attributes[j].attribute_value==selected_attribute_value) {
has_selected_attribute = true;
}
}
}
if (has_selected_attribute && (match_score > previous_match_score)) {
previous_match_score = match_score;
matched = variant;
}
}
if (matched) {
for (var j in matched.attributes) {
var attr = matched.attributes[j];
$('[itemscope]')
.find(repl('.item-view-attribute .form-control[data-attribute="%(attribute)s"]', attr))
.val(attr.attribute_value);
}
return matched.name;
}
}
function get_selected_attributes() {
var attributes = {};
$('[itemscope]').find(".item-view-attribute .form-control").each(function() {
attributes[$(this).attr('data-attribute')] = $(this).val();
});
return attributes;
}

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr
from frappe.utils import cstr, nowdate
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
no_cache = 1
@@ -14,7 +14,11 @@ def get_product_list(search=None, start=0, limit=10):
# base query
query = """select name, item_name, page_name, website_image, thumbnail, item_group,
web_long_description as website_description, parent_website_route
from `tabItem` where show_in_website = 1 and (variant_of is null or variant_of = '')"""
from `tabItem`
where show_in_website = 1
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and (variant_of is null or variant_of = '')"""
# search term condition
if search:
@@ -29,6 +33,7 @@ def get_product_list(search=None, start=0, limit=10):
data = frappe.db.sql(query, {
"search": search,
"today": nowdate()
}, as_dict=1)
for d in data:

View File

@@ -674,7 +674,7 @@ The tax rate you define here will be the standard tax rate for all **Items**. If
#### Description of Columns
1. Calculation Type:
1. Calculation Type:
- This can be on **Net Total** (that is the sum of basic amount).
- **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.
- **Actual** (as mentioned).
@@ -685,19 +685,19 @@ The tax rate you define here will be the standard tax rate for all **Items**. If
6. Amount: Tax amount.
7. Total: Cumulative total to this point.
8. Enter Row: If based on ""Previous Row Total"" you can select the row number which will be taken as a base for this calculation (default is the previous row).
9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.","Mẫu thuế tiêu chuẩn có thể được áp dụng cho tất cả các giao dịch bán hàng. Mẫu này có thể chứa danh sách của người đứng đầu và thuế cũng khác người đứng đầu chi phí / thu nhập như ""Vận chuyển"", ""bảo hiểm"", ""Xử lý"" vv
9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.","Mẫu thuế tiêu chuẩn có thể được áp dụng cho tất cả các giao dịch bán hàng. Mẫu này có thể chứa danh sách của người đứng đầu và thuế cũng khác người đứng đầu chi phí / thu nhập như ""Vận chuyển"", ""bảo hiểm"", ""Xử lý"" vv
#### Chú ý Các mức thuế suất bạn xác định đây sẽ là mức thuế suất tiêu chuẩn cho tất cả các mục ** **. Nếu có những mục ** ** mà có mức giá khác nhau, chúng phải được thêm vào trong các mục ** ** Thuế bảng trong mục ** ** master.
#### Mô tả Cột
#### Mô tả Cột
1. Loại tính:
1. Loại tính:
- Điều này có thể được trên Net ** Tổng số ** (đó là tổng số tiền cơ bản).
- ** Mở Row Previous Total / Số tiền ** (cho các loại thuế, phí tích lũy). Nếu bạn chọn tùy chọn này, thuế sẽ được áp dụng như là một tỷ lệ phần trăm của các dòng trước đó (theo Biểu thuế) hoặc tổng số tiền.
- ** ** Thực tế (như đã đề cập).
2. Tài khoản Head: Các tài khoản sổ cái theo đó thuế này sẽ được đặt
2. Tài khoản Head: Các tài khoản sổ cái theo đó thuế này sẽ được đặt
3. Trung tâm chi phí: Nếu thuế / phí là một khoản thu nhập (như vận chuyển) hoặc chi phí nó cần phải được đặt trước một Trung tâm chi phí.
4. Mô tả: Mô tả về thuế (sẽ được in trên hoá đơn / dấu ngoặc kép).
5. Rate: Thuế suất.
@@ -2015,7 +2015,7 @@ The tax rate you define here will be the standard tax rate for all **Items**. If
#### Description of Columns
1. Calculation Type:
1. Calculation Type:
- This can be on **Net Total** (that is the sum of basic amount).
- **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.
- **Actual** (as mentioned).
@@ -2027,19 +2027,19 @@ The tax rate you define here will be the standard tax rate for all **Items**. If
7. Total: Cumulative total to this point.
8. Enter Row: If based on ""Previous Row Total"" you can select the row number which will be taken as a base for this calculation (default is the previous row).
9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.
10. Add or Deduct: Whether you want to add or deduct the tax.","Mẫu thuế tiêu chuẩn có thể được áp dụng cho tất cả các giao dịch mua hàng. Mẫu này có thể chứa danh sách của người đứng đầu về thuế và cũng đứng đầu chi phí khác như ""Vận chuyển"", ""bảo hiểm"", ""Xử lý"" vv
10. Add or Deduct: Whether you want to add or deduct the tax.","Mẫu thuế tiêu chuẩn có thể được áp dụng cho tất cả các giao dịch mua hàng. Mẫu này có thể chứa danh sách của người đứng đầu về thuế và cũng đứng đầu chi phí khác như ""Vận chuyển"", ""bảo hiểm"", ""Xử lý"" vv
#### Chú ý Các mức thuế bạn xác định ở đây sẽ là mức thuế suất tiêu chuẩn cho tất cả các mục ** **. Nếu có những mục ** ** mà có mức giá khác nhau, chúng phải được thêm vào trong các mục ** ** Thuế bảng trong mục ** ** master.
#### Mô tả Cột
#### Mô tả Cột
1. Loại tính:
1. Loại tính:
- Điều này có thể được trên Net ** Tổng số ** (đó là tổng số tiền cơ bản).
- ** Mở Row Previous Total / Số tiền ** (cho các loại thuế, phí tích lũy). Nếu bạn chọn tùy chọn này, thuế sẽ được áp dụng như là một tỷ lệ phần trăm của các dòng trước đó (theo Biểu thuế) hoặc tổng số tiền.
- ** ** Thực tế (như đã đề cập).
2. Tài khoản Head: Các tài khoản sổ cái theo đó thuế này sẽ được đặt
2. Tài khoản Head: Các tài khoản sổ cái theo đó thuế này sẽ được đặt
3. Trung tâm chi phí: Nếu thuế / phí là một khoản thu nhập (như vận chuyển) hoặc chi phí nó cần phải được đặt trước một Trung tâm chi phí.
4. Mô tả: Mô tả về thuế (sẽ được in trên hoá đơn / dấu ngoặc kép).
5. Rate: Thuế suất.
@@ -2225,7 +2225,7 @@ Examples:
1. Ways of addressing disputes, indemnity, liability, etc.
1. Address and Contact of your Company.","Điều khoản và Điều kiện có thể được thêm vào để bán hàng và mua tiêu chuẩn.
Ví dụ:
Ví dụ:
1. Hiệu lực của đề nghị.
1. Điều khoản thanh toán (Trong Advance, On Credit, phần trước vv).
@@ -2234,7 +2234,7 @@ Examples:
1. Bảo hành nếu có.
1. Trả Policy.
1. Điều khoản vận chuyển, nếu áp dụng.
1. Cách giải quyết tranh chấp, bồi thường, trách nhiệm pháp lý, vv
1. Cách giải quyết tranh chấp, bồi thường, trách nhiệm pháp lý, vv
1. Địa chỉ và liên hệ của công ty của bạn."
DocType: Attendance,Leave Type,Loại bỏ
apps/erpnext/erpnext/controllers/stock_controller.py +172,Expense / Difference account ({0}) must be a 'Profit or Loss' account,"Chi phí tài khoản / khác biệt ({0}) phải là một ""lợi nhuận hoặc lỗ 'tài khoản"
@@ -3125,7 +3125,7 @@ DocType: Accounts Settings,"If enabled, the system will post accounting entries
apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/industry_type.py +15,Brokerage,Môi giới
DocType: Address,Postal Code,Mã bưu chính
DocType: Production Order Operation,"in Minutes
Updated via 'Time Log'","trong Minutes
Updated via 'Time Log'","trong Minutes
Cập nhật qua 'Giờ'"
DocType: Customer,From Lead,Từ chì
apps/erpnext/erpnext/config/manufacturing.py +19,Orders released for production.,Đơn đặt hàng phát hành để sản xuất.
@@ -3302,7 +3302,7 @@ apps/erpnext/erpnext/selling/page/sales_browser/sales_browser.js +121,New {0} Na
apps/erpnext/erpnext/controllers/recurring_document.py +128,Please find attached {0} #{1},{0} # Xin vui lòng tìm thấy kèm theo {1}
DocType: Job Applicant,Applicant Name,Tên đơn
DocType: Authorization Rule,Customer / Item Name,Khách hàng / Item Name
DocType: Product Bundle,"Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**.
DocType: Product Bundle,"Aggregate group of **Items** into another **Item**. This is useful if you are bundling a certain **Items** into a package and you maintain stock of the packed **Items** and not the aggregate **Item**.
The package **Item** will have ""Is Stock Item"" as ""No"" and ""Is Sales Item"" as ""Yes"".
@@ -3444,17 +3444,17 @@ DocType: Address Template,"<h4>Default Template</h4>
{% if phone %}Phone: {{ phone }}&lt;br&gt;{% endif -%}
{% if fax %}Fax: {{ fax }}&lt;br&gt;{% endif -%}
{% if email_id %}Email: {{ email_id }}&lt;br&gt;{% endif -%}
</code></pre>","<H4> Default Template </ h4>
<p> Sử dụng <a href=""http://jinja.pocoo.org/docs/templates/""> Jinja Templating </a> và tất cả các lĩnh vực của Địa chỉ ( bao gồm Tuỳ chỉnh Fields nếu có) sẽ có sẵn </ p>
<pre> <code> {{address_line1}} & lt; br & gt;
</code></pre>","<H4> Default Template </ h4>
<p> Sử dụng <a href=""http://jinja.pocoo.org/docs/templates/""> Jinja Templating </a> và tất cả các lĩnh vực của Địa chỉ ( bao gồm Tuỳ chỉnh Fields nếu có) sẽ có sẵn </ p>
<pre> <code> {{address_line1}} & lt; br & gt;
{% nếu address_line2%} {{address_line2}} & lt; br & gt; { endif% -%} {{
thành phố}} & lt; br & gt;
thành phố}} & lt; br & gt;
{% nếu nhà nước%} {{}} nhà nước & lt; br & gt; {% endif -%} {
% nếu mã pin%} PIN: {{mã pin}} & lt; br & gt; {% endif -%}
{{country}} & lt; br & gt;
{% nếu điện thoại%} Điện thoại: {{phone}} & lt; br & gt; { % endif -%}
{% nếu fax%} Fax: {{fax}} & lt; br & gt; {% endif -%}
{% nếu email_id%} Email: {{email_id}} & lt; br & gt ; {% endif -}%
% nếu mã pin%} PIN: {{mã pin}} & lt; br & gt; {% endif -%}
{{country}} & lt; br & gt;
{% nếu điện thoại%} Điện thoại: {{phone}} & lt; br & gt; { % endif -%}
{% nếu fax%} Fax: {{fax}} & lt; br & gt; {% endif -%}
{% nếu email_id%} Email: {{email_id}} & lt; br & gt ; {% endif -}%
</ code> </ pre>"
DocType: Salary Slip Deduction,Default Amount,Số tiền mặc định
apps/erpnext/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +89,Warehouse not found in the system,Kho không tìm thấy trong hệ thống
@@ -3645,7 +3645,7 @@ apps/erpnext/erpnext/crm/doctype/newsletter_list/newsletter_list.js +40,New News
apps/erpnext/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py +157,Start date should be less than end date for Item {0},Ngày bắt đầu phải nhỏ hơn ngày kết thúc cho hàng {0}
apps/erpnext/erpnext/stock/doctype/item/item.js +17,Show Balance,Hiện Balance
DocType: Item,"Example: ABCD.#####
If series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.","Ví dụ:. ABCD #####
If series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.","Ví dụ:. ABCD #####
Nếu series được thiết lập và Serial No không được đề cập trong các giao dịch, số serial sau đó tự động sẽ được tạo ra dựa trên series này. Nếu bạn luôn muốn đề cập đến một cách rõ ràng nối tiếp Nos cho mặt hàng này. để trống này."
DocType: Upload Attendance,Upload Attendance,Tải lên tham dự
apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.js +119,BOM and Manufacturing Quantity are required,BOM và Sản xuất Số lượng được yêu cầu
@@ -3776,7 +3776,7 @@ DocType: Batch,Batch,Hàng loạt
apps/erpnext/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +53,Balance,Balance
DocType: Project,Total Expense Claim (via Expense Claims),Tổng số yêu cầu bồi thường chi phí (thông qua Tuyên bố Expense)
DocType: User,Gender,Giới Tính
DocType: Journal Entry,Debit Note,"Một lưu ghi nợ là do bên cho mượn, nợ và phục vụ như là một trong hai thông báo về một khoản nợ sẽ sớm nhận được hoá đơn hoặc một lời nhắc nhở đối với khoản nợ mà trước đây được lập hoá đơn và hiện đang nổi bật."
DocType: Journal Entry,Debit Note,"nợ Ghi"
DocType: Stock Entry,As per Stock UOM,Theo Cổ UOM
apps/erpnext/erpnext/stock/doctype/batch/batch_list.js +7,Not Expired,Không hết hạn
DocType: Journal Entry,Total Debit,Tổng số Nợ
1 DocType: Employee Salary Mode Chế độ tiền lương
674 DocType: Process Payroll Send Email Gởi thư
675 apps/erpnext/erpnext/buying/doctype/supplier/supplier.py +88 No Permission Không phép
676 DocType: Company Default Bank Account Tài khoản Ngân hàng mặc định
677 apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py +47 To filter based on Party, select Party Type first Để lọc dựa vào Đảng, Đảng chọn Gõ đầu tiên
678 apps/erpnext/erpnext/controllers/sales_and_purchase_return.py +48 'Update Stock' can not be checked because items are not delivered via {0} &#39;Update Cổ&#39; không thể được kiểm tra vì mục này không được cung cấp thông qua {0}
679 apps/erpnext/erpnext/setup/page/setup_wizard/setup_wizard.js +626 Nos lớp
680 DocType: Item Items with higher weightage will be shown higher Mục weightage cao sẽ được hiển thị cao hơn
685 DocType: Item If subcontracted to a vendor Nếu hợp đồng phụ với một nhà cung cấp
686 apps/erpnext/erpnext/manufacturing/page/bom_browser/bom_browser.js +17 Select BOM to start Chọn BOM để bắt đầu
687 DocType: SMS Center All Customer Contact Tất cả các khách hàng Liên hệ
688 apps/erpnext/erpnext/config/stock.py +64 Upload stock balance via csv. Tải lên số dư chứng khoán thông qua csv.
689 apps/erpnext/erpnext/setup/doctype/email_digest/email_digest.js +27 Send Now Bây giờ gửi
690 apps/erpnext/erpnext/setup/doctype/email_digest/email_digest.js +27 Send Now Support Analytics Bây giờ gửi Hỗ trợ Analytics
Support Analytics Hỗ trợ Analytics
691 DocType: Item Website Warehouse Trang web kho
692 DocType: Sales Invoice The day of the month on which auto invoice will be generated e.g. 05, 28 etc Các ngày trong tháng mà tự động hóa đơn sẽ được tạo ra ví dụ như 05, 28 vv
693 apps/erpnext/erpnext/hr/doctype/appraisal/appraisal.js +49 Score must be less than or equal to 5 Điểm số phải nhỏ hơn hoặc bằng 5
694 apps/erpnext/erpnext/config/accounts.py +169 C-Form records Hồ sơ C-Mẫu
695 apps/erpnext/erpnext/config/selling.py +294 Customer and Supplier Khách hàng và Nhà cung cấp
696 DocType: Email Digest Email Digest Settings Email chỉnh Digest
697 apps/erpnext/erpnext/config/support.py +13 Support queries from customers. Hỗ trợ các truy vấn từ khách hàng.
698 DocType: Features Setup To enable "Point of Sale" features Để kích hoạt tính năng &quot;Point of Sale&quot; tính năng
699 DocType: Bin Moving Average Rate Tỷ lệ trung bình di chuyển
700 DocType: Production Planning Tool Select Items Chọn mục
701 apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py +321 {0} against Bill {1} dated {2} {0} với Bill {1} ​​{2} ngày
702 DocType: Comment Reference Name Tên tài liệu tham khảo
703 DocType: Maintenance Visit Completion Status Tình trạng hoàn thành
2015 DocType: Account Account Type Loại tài khoản
2016 apps/erpnext/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py +212 Maintenance Schedule is not generated for all the items. Please click on 'Generate Schedule' Lịch trình bảo trì không được tạo ra cho tất cả các mục. Vui lòng click vào 'Tạo lịch'
2017 To Produce Để sản xuất
2018 apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +119 For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included Đối với hàng {0} trong {1}. Để bao gồm {2} tỷ lệ Item, hàng {3} cũng phải được bao gồm
2019 DocType: Packing Slip Identification of the package for the delivery (for print) Xác định các gói cho việc cung cấp (đối với in)
2020 DocType: Bin Reserved Quantity Ltd Số lượng
2021 DocType: Landed Cost Voucher Purchase Receipt Items Mua hóa đơn mục
2027 apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +625 Delivery Giao hàng
2028 DocType: Stock Reconciliation Item Current Qty Số lượng hiện tại
2029 DocType: BOM Item See "Rate Of Materials Based On" in Costing Section Xem "Tỷ lệ Of Vật liệu Dựa trên" trong mục Chi phí
2030 DocType: Appraisal Goal Key Responsibility Area Diện tích Trách nhiệm chính
2031 DocType: Item Reorder Material Request Type Tài liệu theo yêu cầu Loại
2032 DocType: Item Reorder apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +84 Material Request Type Row {0}: UOM Conversion Factor is mandatory Tài liệu theo yêu cầu Loại Row {0}: Ươm Conversion Factor là bắt buộc
apps/erpnext/erpnext/stock/doctype/stock_entry/stock_entry.py +84 Row {0}: UOM Conversion Factor is mandatory Row {0}: Ươm Conversion Factor là bắt buộc
2033 apps/frappe/frappe/desk/moduleview.py +61 Documents Tài liệu
2034 apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.html +17 Ref Tài liệu tham khảo
2035 DocType: Cost Center Cost Center Trung tâm chi phí
2036 apps/erpnext/erpnext/stock/report/stock_ledger/stock_ledger.js +48 Voucher # Chứng từ #
2037 DocType: Notification Control Purchase Order Message Thông báo Mua hàng
2038 DocType: Tax Rule Shipping Country Vận Chuyển Country
2039 DocType: Upload Attendance Upload HTML Tải lên HTML
2040 apps/erpnext/erpnext/controllers/accounts_controller.py +391 Total advance ({0}) against Order {1} cannot be greater \ than the Grand Total ({2}) Tổng số trước ({0}) chống lại thứ tự {1} có thể không được lớn hơn \ Grand Total ({2})
2041 DocType: Employee Relieving Date Giảm ngày
2042 apps/erpnext/erpnext/accounts/doctype/pricing_rule/pricing_rule.js +12 Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria. Quy tắc định giá được thực hiện để ghi đè lên Giá liệt kê / xác định tỷ lệ phần trăm giảm giá, dựa trên một số tiêu chí.
2043 DocType: Serial No Warehouse can only be changed via Stock Entry / Delivery Note / Purchase Receipt Kho chỉ có thể được thay đổi thông qua chứng khoán Entry / Giao hàng tận nơi Lưu ý / mua hóa đơn
2044 DocType: Employee Education Class / Percentage Lớp / Tỷ lệ phần trăm
2045 apps/erpnext/erpnext/setup/page/setup_wizard/install_fixtures.py +92 Head of Marketing and Sales Trưởng phòng Marketing và Bán hàng
2225 apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/operations.py +125 Vibratory finishing Hoàn thiện rung
2226 DocType: Item Customer Detail For the convenience of customers, these codes can be used in print formats like Invoices and Delivery Notes Để thuận tiện cho khách hàng, các mã có thể được sử dụng trong các định dạng như in hóa đơn và giao hàng Ghi chú
2227 DocType: Employee You can enter any date manually Bạn có thể nhập bất kỳ ngày nào tay
2228 DocType: Sales Invoice Advertisement Quảng cáo
2229 apps/erpnext/erpnext/setup/page/setup_wizard/install_fixtures.py +165 Probationary Period Thời gian thử việc
2230 DocType: Customer Group Only leaf nodes are allowed in transaction Chỉ các nút lá được cho phép trong giao dịch
2231 DocType: Expense Claim Expense Approver Người phê duyệt chi phí
2234 apps/erpnext/erpnext/projects/report/daily_time_log_summary/daily_time_log_summary.py +17 To Datetime Để Datetime
2235 DocType: SMS Settings SMS Gateway URL SMS Gateway URL
2236 apps/erpnext/erpnext/config/crm.py +53 Logs for maintaining sms delivery status Logs cho việc duy trì tình trạng giao hàng sms
2237 apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/operations.py +137 Grinding Nghiền
2238 apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/operations.py +34 Shrink wrapping Shrink gói
2239 apps/erpnext/erpnext/setup/doctype/email_digest/templates/default.html +35 Pending Activities Các hoạt động cấp phát
2240 apps/erpnext/erpnext/crm/doctype/newsletter/newsletter.py +166 Confirmed Xác nhận
3125 DocType: System Settings Time Zone Múi giờ
3126 apps/erpnext/erpnext/stock/doctype/warehouse/warehouse.py +104 Warehouse {0} does not exist Kho {0} không tồn tại
3127 apps/erpnext/erpnext/hub_node/page/hub/register_in_hub.html +2 Register For ERPNext Hub Đăng ký các ERPNext Hub
3128 DocType: Monthly Distribution Monthly Distribution Percentages Tỷ lệ phân phối hàng tháng
3129 apps/erpnext/erpnext/stock/doctype/batch/batch.py +16 The selected item cannot have Batch Các sản phẩm được chọn không thể có hàng loạt
3130 DocType: Delivery Note % of materials delivered against this Delivery Note % Nguyên liệu chuyển giao chống lại Giao hàng tận nơi này Lưu ý
3131 apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/operations.py +151 Stapling Máy đóng ghim
3302 apps/erpnext/erpnext/stock/doctype/stock_settings/stock_settings.py +26 `Freeze Stocks Older Than` should be smaller than %d days. `Đóng băng cổ phiếu cũ hơn` nên nhỏ hơn% d ngày.
3303 DocType: Tax Rule Purchase Tax Template Mua Template Thuế
3304 Project wise Stock Tracking Dự án theo dõi chứng khoán khôn ngoan
3305 apps/erpnext/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py +166 Maintenance Schedule {0} exists against {0} Lịch trình bảo trì {0} tồn tại đối với {0}
3306 DocType: Stock Entry Detail Actual Qty (at source/target) Số lượng thực tế (tại nguồn / mục tiêu)
3307 DocType: Item Customer Detail Ref Code Tài liệu tham khảo Mã
3308 apps/erpnext/erpnext/config/hr.py +13 Employee records. Hồ sơ nhân viên.
3444 apps/erpnext/erpnext/hr/doctype/process_payroll/process_payroll.js +28 Do you really want to Submit all Salary Slip for month {0} and year {1} Bạn có thực sự muốn để gửi tất cả các Phiếu lương cho tháng {0} và năm {1}
3445 apps/erpnext/erpnext/crm/doctype/newsletter_list/newsletter_list.js +8 Import Subscribers Subscribers nhập
3446 DocType: Target Detail Target Qty Số lượng mục tiêu
3447 DocType: Attendance Present Nay
3448 apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.py +35 Delivery Note {0} must not be submitted Giao hàng Ghi {0} không phải nộp
3449 DocType: Notification Control Sales Invoice Message Hóa đơn bán hàng nhắn
3450 DocType: Authorization Rule Based On Dựa trên
3451 Ordered Qty Số lượng đặt hàng
3452 DocType: Stock Settings Stock Frozen Upto Cổ đông lạnh HCM,
3453 apps/erpnext/erpnext/config/projects.py +13 Project activity / task. Hoạt động dự án / nhiệm vụ.
3454 apps/erpnext/erpnext/config/hr.py +65 Generate Salary Slips Tạo ra lương Trượt
3455 apps/frappe/frappe/utils/__init__.py +79 {0} is not a valid email id {0} không phải là một id email hợp lệ
3456 apps/erpnext/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +41 Buying must be checked, if Applicable For is selected as {0} Mua phải được kiểm tra, nếu áp dụng Đối với được chọn là {0}
3457 apps/erpnext/erpnext/setup/doctype/authorization_rule/authorization_rule.py +40 Discount must be less than 100 Giảm giá phải được ít hơn 100
3458 DocType: ToDo Low Thấp
3459 DocType: Purchase Invoice Write Off Amount (Company Currency) Viết Tắt Số tiền (Công ty tiền tệ)
3460 apps/erpnext/erpnext/setup/page/setup_wizard/fixtures/operations.py +71 Spinning Spinning
3645 apps/erpnext/erpnext/hr/doctype/salary_slip/salary_slip.py +197 Company Email ID not found, hence mail not sent Công ty Email ID không tìm thấy, do đó thư không gửi
3646 apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py +9 Application of Funds (Assets) Ứng dụng của Quỹ (tài sản)
3647 DocType: Production Planning Tool Filter based on item Lọc dựa trên mục
3648 DocType: Fiscal Year Year Start Date Ngày bắt đầu năm
3649 DocType: Attendance Employee Name Tên nhân viên
3650 DocType: Sales Invoice Rounded Total (Company Currency) Tổng số tròn (Công ty tiền tệ)
3651 apps/erpnext/erpnext/accounts/doctype/account/account.py +115 Cannot covert to Group because Account Type is selected. Không thể bí mật với đoàn vì Loại tài khoản được chọn.
3776 apps/erpnext/erpnext/setup/page/setup_wizard/install_fixtures.py +94 Designer Nhà thiết kế
3777 apps/erpnext/erpnext/config/selling.py +121 Terms and Conditions Template Điều khoản và Điều kiện Template
3778 DocType: Serial No Delivery Details Chi tiết giao hàng
3779 apps/erpnext/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +382 Cost Center is required in row {0} in Taxes table for type {1} Trung tâm chi phí là cần thiết trong hàng {0} trong bảng Thuế cho loại {1}
3780 DocType: Item Automatically create Material Request if quantity falls below this level Tự động tạo Material Request nếu số lượng giảm xuống dưới mức này
3781 Item-wise Purchase Register Item-khôn ngoan mua Đăng ký
3782 DocType: Batch Expiry Date Ngày hết hiệu lực

View File

@@ -1,6 +1,6 @@
from setuptools import setup, find_packages
version = "6.6.0"
version = "6.6.7"
with open("requirements.txt", "r") as f:
install_requires = f.readlines()