mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-25 16:04:46 +00:00
Merge pull request #37153 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
@@ -117,9 +117,6 @@ frappe.ui.form.on('Account', {
|
|||||||
args: {
|
args: {
|
||||||
old: frm.doc.name,
|
old: frm.doc.name,
|
||||||
new: data.name,
|
new: data.name,
|
||||||
is_group: frm.doc.is_group,
|
|
||||||
root_type: frm.doc.root_type,
|
|
||||||
company: frm.doc.company
|
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ class BalanceMismatchError(frappe.ValidationError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidAccountMergeError(frappe.ValidationError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Account(NestedSet):
|
class Account(NestedSet):
|
||||||
nsm_parent_field = "parent_account"
|
nsm_parent_field = "parent_account"
|
||||||
|
|
||||||
@@ -444,24 +448,35 @@ def update_account_number(name, account_name, account_number=None, from_descenda
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def merge_account(old, new, is_group, root_type, company):
|
def merge_account(old, new):
|
||||||
# Validate properties before merging
|
# Validate properties before merging
|
||||||
if not frappe.db.exists("Account", new):
|
new_account = frappe.get_cached_doc("Account", new)
|
||||||
|
old_account = frappe.get_cached_doc("Account", old)
|
||||||
|
|
||||||
|
if not new_account:
|
||||||
throw(_("Account {0} does not exist").format(new))
|
throw(_("Account {0} does not exist").format(new))
|
||||||
|
|
||||||
val = list(frappe.db.get_value("Account", new, ["is_group", "root_type", "company"]))
|
if (
|
||||||
|
cint(new_account.is_group),
|
||||||
if val != [cint(is_group), root_type, company]:
|
new_account.root_type,
|
||||||
|
new_account.company,
|
||||||
|
cstr(new_account.account_currency),
|
||||||
|
) != (
|
||||||
|
cint(old_account.is_group),
|
||||||
|
old_account.root_type,
|
||||||
|
old_account.company,
|
||||||
|
cstr(old_account.account_currency),
|
||||||
|
):
|
||||||
throw(
|
throw(
|
||||||
_(
|
msg=_(
|
||||||
"""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""
|
"""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company and Account Currency"""
|
||||||
)
|
),
|
||||||
|
title=("Invalid Accounts"),
|
||||||
|
exc=InvalidAccountMergeError,
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_group and frappe.db.get_value("Account", new, "parent_account") == old:
|
if old_account.is_group and new_account.parent_account == old:
|
||||||
frappe.db.set_value(
|
new_account.db_set("parent_account", frappe.get_cached_value("Account", old, "parent_account"))
|
||||||
"Account", new, "parent_account", frappe.db.get_value("Account", old, "parent_account")
|
|
||||||
)
|
|
||||||
|
|
||||||
frappe.rename_doc("Account", old, new, merge=1, force=1)
|
frappe.rename_doc("Account", old, new, merge=1, force=1)
|
||||||
|
|
||||||
|
|||||||
@@ -56,36 +56,41 @@ frappe.treeview_settings["Account"] = {
|
|||||||
accounts = nodes;
|
accounts = nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const get_balances = frappe.call({
|
frappe.db.get_single_value("Accounts Settings", "show_balance_in_coa").then((value) => {
|
||||||
method: 'erpnext.accounts.utils.get_account_balances',
|
if(value) {
|
||||||
args: {
|
|
||||||
accounts: accounts,
|
|
||||||
company: cur_tree.args.company
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
get_balances.then(r => {
|
const get_balances = frappe.call({
|
||||||
if (!r.message || r.message.length == 0) return;
|
method: 'erpnext.accounts.utils.get_account_balances',
|
||||||
|
args: {
|
||||||
|
accounts: accounts,
|
||||||
|
company: cur_tree.args.company
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
for (let account of r.message) {
|
get_balances.then(r => {
|
||||||
|
if (!r.message || r.message.length == 0) return;
|
||||||
|
|
||||||
const node = cur_tree.nodes && cur_tree.nodes[account.value];
|
for (let account of r.message) {
|
||||||
if (!node || node.is_root) continue;
|
|
||||||
|
|
||||||
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
const node = cur_tree.nodes && cur_tree.nodes[account.value];
|
||||||
const balance = account.balance_in_account_currency || account.balance;
|
if (!node || node.is_root) continue;
|
||||||
const dr_or_cr = balance > 0 ? "Dr": "Cr";
|
|
||||||
const format = (value, currency) => format_currency(Math.abs(value), currency);
|
|
||||||
|
|
||||||
if (account.balance!==undefined) {
|
// show Dr if positive since balance is calculated as debit - credit else show Cr
|
||||||
node.parent && node.parent.find('.balance-area').remove();
|
const balance = account.balance_in_account_currency || account.balance;
|
||||||
$('<span class="balance-area pull-right">'
|
const dr_or_cr = balance > 0 ? "Dr": "Cr";
|
||||||
+ (account.balance_in_account_currency ?
|
const format = (value, currency) => format_currency(Math.abs(value), currency);
|
||||||
(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
|
|
||||||
+ format(account.balance, account.company_currency)
|
if (account.balance!==undefined) {
|
||||||
+ " " + dr_or_cr
|
node.parent && node.parent.find('.balance-area').remove();
|
||||||
+ '</span>').insertBefore(node.$ul);
|
$('<span class="balance-area pull-right">'
|
||||||
}
|
+ (account.balance_in_account_currency ?
|
||||||
|
(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
|
||||||
|
+ format(account.balance, account.company_currency)
|
||||||
|
+ " " + dr_or_cr
|
||||||
|
+ '</span>').insertBefore(node.$ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import unittest
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.test_runner import make_test_records
|
from frappe.test_runner import make_test_records
|
||||||
|
|
||||||
from erpnext.accounts.doctype.account.account import merge_account, update_account_number
|
from erpnext.accounts.doctype.account.account import (
|
||||||
|
InvalidAccountMergeError,
|
||||||
|
merge_account,
|
||||||
|
update_account_number,
|
||||||
|
)
|
||||||
from erpnext.stock import get_company_default_inventory_account, get_warehouse_account
|
from erpnext.stock import get_company_default_inventory_account, get_warehouse_account
|
||||||
|
|
||||||
test_dependencies = ["Company"]
|
test_dependencies = ["Company"]
|
||||||
@@ -47,49 +51,53 @@ class TestAccount(unittest.TestCase):
|
|||||||
frappe.delete_doc("Account", "1211-11-4 - 6 - Debtors 1 - Test - - _TC")
|
frappe.delete_doc("Account", "1211-11-4 - 6 - Debtors 1 - Test - - _TC")
|
||||||
|
|
||||||
def test_merge_account(self):
|
def test_merge_account(self):
|
||||||
if not frappe.db.exists("Account", "Current Assets - _TC"):
|
create_account(
|
||||||
acc = frappe.new_doc("Account")
|
account_name="Current Assets",
|
||||||
acc.account_name = "Current Assets"
|
is_group=1,
|
||||||
acc.is_group = 1
|
parent_account="Application of Funds (Assets) - _TC",
|
||||||
acc.parent_account = "Application of Funds (Assets) - _TC"
|
company="_Test Company",
|
||||||
acc.company = "_Test Company"
|
)
|
||||||
acc.insert()
|
|
||||||
if not frappe.db.exists("Account", "Securities and Deposits - _TC"):
|
create_account(
|
||||||
acc = frappe.new_doc("Account")
|
account_name="Securities and Deposits",
|
||||||
acc.account_name = "Securities and Deposits"
|
is_group=1,
|
||||||
acc.parent_account = "Current Assets - _TC"
|
parent_account="Current Assets - _TC",
|
||||||
acc.is_group = 1
|
company="_Test Company",
|
||||||
acc.company = "_Test Company"
|
)
|
||||||
acc.insert()
|
|
||||||
if not frappe.db.exists("Account", "Earnest Money - _TC"):
|
create_account(
|
||||||
acc = frappe.new_doc("Account")
|
account_name="Earnest Money",
|
||||||
acc.account_name = "Earnest Money"
|
parent_account="Securities and Deposits - _TC",
|
||||||
acc.parent_account = "Securities and Deposits - _TC"
|
company="_Test Company",
|
||||||
acc.company = "_Test Company"
|
)
|
||||||
acc.insert()
|
|
||||||
if not frappe.db.exists("Account", "Cash In Hand - _TC"):
|
create_account(
|
||||||
acc = frappe.new_doc("Account")
|
account_name="Cash In Hand",
|
||||||
acc.account_name = "Cash In Hand"
|
is_group=1,
|
||||||
acc.is_group = 1
|
parent_account="Current Assets - _TC",
|
||||||
acc.parent_account = "Current Assets - _TC"
|
company="_Test Company",
|
||||||
acc.company = "_Test Company"
|
)
|
||||||
acc.insert()
|
|
||||||
if not frappe.db.exists("Account", "Accumulated Depreciation - _TC"):
|
create_account(
|
||||||
acc = frappe.new_doc("Account")
|
account_name="Receivable INR",
|
||||||
acc.account_name = "Accumulated Depreciation"
|
parent_account="Current Assets - _TC",
|
||||||
acc.parent_account = "Fixed Assets - _TC"
|
company="_Test Company",
|
||||||
acc.company = "_Test Company"
|
account_currency="INR",
|
||||||
acc.account_type = "Accumulated Depreciation"
|
)
|
||||||
acc.insert()
|
|
||||||
|
create_account(
|
||||||
|
account_name="Receivable USD",
|
||||||
|
parent_account="Current Assets - _TC",
|
||||||
|
company="_Test Company",
|
||||||
|
account_currency="USD",
|
||||||
|
)
|
||||||
|
|
||||||
doc = frappe.get_doc("Account", "Securities and Deposits - _TC")
|
|
||||||
parent = frappe.db.get_value("Account", "Earnest Money - _TC", "parent_account")
|
parent = frappe.db.get_value("Account", "Earnest Money - _TC", "parent_account")
|
||||||
|
|
||||||
self.assertEqual(parent, "Securities and Deposits - _TC")
|
self.assertEqual(parent, "Securities and Deposits - _TC")
|
||||||
|
|
||||||
merge_account(
|
merge_account("Securities and Deposits - _TC", "Cash In Hand - _TC")
|
||||||
"Securities and Deposits - _TC", "Cash In Hand - _TC", doc.is_group, doc.root_type, doc.company
|
|
||||||
)
|
|
||||||
parent = frappe.db.get_value("Account", "Earnest Money - _TC", "parent_account")
|
parent = frappe.db.get_value("Account", "Earnest Money - _TC", "parent_account")
|
||||||
|
|
||||||
# Parent account of the child account changes after merging
|
# Parent account of the child account changes after merging
|
||||||
@@ -98,30 +106,28 @@ class TestAccount(unittest.TestCase):
|
|||||||
# Old account doesn't exist after merging
|
# Old account doesn't exist after merging
|
||||||
self.assertFalse(frappe.db.exists("Account", "Securities and Deposits - _TC"))
|
self.assertFalse(frappe.db.exists("Account", "Securities and Deposits - _TC"))
|
||||||
|
|
||||||
doc = frappe.get_doc("Account", "Current Assets - _TC")
|
|
||||||
|
|
||||||
# Raise error as is_group property doesn't match
|
# Raise error as is_group property doesn't match
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
frappe.ValidationError,
|
InvalidAccountMergeError,
|
||||||
merge_account,
|
merge_account,
|
||||||
"Current Assets - _TC",
|
"Current Assets - _TC",
|
||||||
"Accumulated Depreciation - _TC",
|
"Accumulated Depreciation - _TC",
|
||||||
doc.is_group,
|
|
||||||
doc.root_type,
|
|
||||||
doc.company,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
doc = frappe.get_doc("Account", "Capital Stock - _TC")
|
|
||||||
|
|
||||||
# Raise error as root_type property doesn't match
|
# Raise error as root_type property doesn't match
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
frappe.ValidationError,
|
InvalidAccountMergeError,
|
||||||
merge_account,
|
merge_account,
|
||||||
"Capital Stock - _TC",
|
"Capital Stock - _TC",
|
||||||
"Softwares - _TC",
|
"Softwares - _TC",
|
||||||
doc.is_group,
|
)
|
||||||
doc.root_type,
|
|
||||||
doc.company,
|
# Raise error as currency doesn't match
|
||||||
|
self.assertRaises(
|
||||||
|
InvalidAccountMergeError,
|
||||||
|
merge_account,
|
||||||
|
"Receivable INR - _TC",
|
||||||
|
"Receivable USD - _TC",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_account_sync(self):
|
def test_account_sync(self):
|
||||||
@@ -400,11 +406,20 @@ def create_account(**kwargs):
|
|||||||
"Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")}
|
"Account", filters={"account_name": kwargs.get("account_name"), "company": kwargs.get("company")}
|
||||||
)
|
)
|
||||||
if account:
|
if account:
|
||||||
return account
|
account = frappe.get_doc("Account", account)
|
||||||
|
account.update(
|
||||||
|
dict(
|
||||||
|
is_group=kwargs.get("is_group", 0),
|
||||||
|
parent_account=kwargs.get("parent_account"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
account.save()
|
||||||
|
return account.name
|
||||||
else:
|
else:
|
||||||
account = frappe.get_doc(
|
account = frappe.get_doc(
|
||||||
dict(
|
dict(
|
||||||
doctype="Account",
|
doctype="Account",
|
||||||
|
is_group=kwargs.get("is_group", 0),
|
||||||
account_name=kwargs.get("account_name"),
|
account_name=kwargs.get("account_name"),
|
||||||
account_type=kwargs.get("account_type"),
|
account_type=kwargs.get("account_type"),
|
||||||
parent_account=kwargs.get("parent_account"),
|
parent_account=kwargs.get("parent_account"),
|
||||||
|
|||||||
@@ -66,7 +66,9 @@
|
|||||||
"report_settings_sb",
|
"report_settings_sb",
|
||||||
"banking_tab",
|
"banking_tab",
|
||||||
"enable_party_matching",
|
"enable_party_matching",
|
||||||
"enable_fuzzy_matching"
|
"enable_fuzzy_matching",
|
||||||
|
"tab_break_dpet",
|
||||||
|
"show_balance_in_coa"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -416,6 +418,17 @@
|
|||||||
"fieldname": "ignore_account_closing_balance",
|
"fieldname": "ignore_account_closing_balance",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Ignore Account Closing Balance"
|
"label": "Ignore Account Closing Balance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "tab_break_dpet",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Chart Of Accounts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"fieldname": "show_balance_in_coa",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Show Balances in Chart Of Accounts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "icon-cog",
|
"icon": "icon-cog",
|
||||||
|
|||||||
@@ -49,9 +49,6 @@ def start_merge(docname):
|
|||||||
merge_account(
|
merge_account(
|
||||||
row.account,
|
row.account,
|
||||||
ledger_merge.account,
|
ledger_merge.account,
|
||||||
ledger_merge.is_group,
|
|
||||||
ledger_merge.root_type,
|
|
||||||
ledger_merge.company,
|
|
||||||
)
|
)
|
||||||
row.db_set("merged", 1)
|
row.db_set("merged", 1)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|||||||
@@ -1455,6 +1455,14 @@ def get_outstanding_reference_documents(args):
|
|||||||
fieldname, args.get(date_fields[0]), args.get(date_fields[1])
|
fieldname, args.get(date_fields[0]), args.get(date_fields[1])
|
||||||
)
|
)
|
||||||
posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
|
posting_and_due_date.append(ple[fieldname][args.get(date_fields[0]) : args.get(date_fields[1])])
|
||||||
|
elif args.get(date_fields[0]):
|
||||||
|
# if only from date is supplied
|
||||||
|
condition += " and {0} >= '{1}'".format(fieldname, args.get(date_fields[0]))
|
||||||
|
posting_and_due_date.append(ple[fieldname].gte(args.get(date_fields[0])))
|
||||||
|
elif args.get(date_fields[1]):
|
||||||
|
# if only to date is supplied
|
||||||
|
condition += " and {0} <= '{1}'".format(fieldname, args.get(date_fields[1]))
|
||||||
|
posting_and_due_date.append(ple[fieldname].lte(args.get(date_fields[1])))
|
||||||
|
|
||||||
if args.get("company"):
|
if args.get("company"):
|
||||||
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
|
condition += " and company = {0}".format(frappe.db.escape(args.get("company")))
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
@@ -43,7 +45,6 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.validate_debit_to_acc()
|
self.validate_debit_to_acc()
|
||||||
self.validate_write_off_account()
|
self.validate_write_off_account()
|
||||||
self.validate_change_amount()
|
self.validate_change_amount()
|
||||||
self.validate_duplicate_serial_and_batch_no()
|
|
||||||
self.validate_change_account()
|
self.validate_change_account()
|
||||||
self.validate_item_cost_centers()
|
self.validate_item_cost_centers()
|
||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
@@ -56,6 +57,7 @@ class POSInvoice(SalesInvoice):
|
|||||||
self.validate_payment_amount()
|
self.validate_payment_amount()
|
||||||
self.validate_loyalty_transaction()
|
self.validate_loyalty_transaction()
|
||||||
self.validate_company_with_pos_company()
|
self.validate_company_with_pos_company()
|
||||||
|
self.validate_duplicate_serial_no()
|
||||||
if self.coupon_code:
|
if self.coupon_code:
|
||||||
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
|
from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
|
||||||
|
|
||||||
@@ -156,27 +158,18 @@ class POSInvoice(SalesInvoice):
|
|||||||
title=_("Item Unavailable"),
|
title=_("Item Unavailable"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def validate_duplicate_serial_and_batch_no(self):
|
def validate_duplicate_serial_no(self):
|
||||||
serial_nos = []
|
serial_nos = []
|
||||||
batch_nos = []
|
|
||||||
|
|
||||||
for row in self.get("items"):
|
for row in self.get("items"):
|
||||||
if row.serial_no:
|
if row.serial_no:
|
||||||
serial_nos = row.serial_no.split("\n")
|
serial_nos = row.serial_no.split("\n")
|
||||||
|
|
||||||
if row.batch_no and not row.serial_no:
|
|
||||||
batch_nos.append(row.batch_no)
|
|
||||||
|
|
||||||
if serial_nos:
|
if serial_nos:
|
||||||
for key, value in collections.Counter(serial_nos).items():
|
for key, value in collections.Counter(serial_nos).items():
|
||||||
if value > 1:
|
if value > 1:
|
||||||
frappe.throw(_("Duplicate Serial No {0} found").format("key"))
|
frappe.throw(_("Duplicate Serial No {0} found").format("key"))
|
||||||
|
|
||||||
if batch_nos:
|
|
||||||
for key, value in collections.Counter(batch_nos).items():
|
|
||||||
if value > 1:
|
|
||||||
frappe.throw(_("Duplicate Batch No {0} found").format("key"))
|
|
||||||
|
|
||||||
def validate_pos_reserved_batch_qty(self, item):
|
def validate_pos_reserved_batch_qty(self, item):
|
||||||
filters = {"item_code": item.item_code, "warehouse": item.warehouse, "batch_no": item.batch_no}
|
filters = {"item_code": item.item_code, "warehouse": item.warehouse, "batch_no": item.batch_no}
|
||||||
|
|
||||||
@@ -683,7 +676,7 @@ def get_bundle_availability(bundle_item_code, warehouse):
|
|||||||
item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse)
|
item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse)
|
||||||
available_qty = item_bin_qty - item_pos_reserved_qty
|
available_qty = item_bin_qty - item_pos_reserved_qty
|
||||||
|
|
||||||
max_available_bundles = available_qty / item.stock_qty
|
max_available_bundles = available_qty / item.qty
|
||||||
if bundle_bin_qty > max_available_bundles and frappe.get_value(
|
if bundle_bin_qty > max_available_bundles and frappe.get_value(
|
||||||
"Item", item.item_code, "is_stock_item"
|
"Item", item.item_code, "is_stock_item"
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -464,6 +464,37 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
pos2.insert()
|
pos2.insert()
|
||||||
self.assertRaises(frappe.ValidationError, pos2.submit)
|
self.assertRaises(frappe.ValidationError, pos2.submit)
|
||||||
|
|
||||||
|
def test_pos_invoice_with_duplicate_serial_no(self):
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||||
|
|
||||||
|
se = make_serialized_item(
|
||||||
|
company="_Test Company",
|
||||||
|
target_warehouse="Stores - _TC",
|
||||||
|
cost_center="Main - _TC",
|
||||||
|
expense_account="Cost of Goods Sold - _TC",
|
||||||
|
)
|
||||||
|
|
||||||
|
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
|
||||||
|
|
||||||
|
pos = create_pos_invoice(
|
||||||
|
company="_Test Company",
|
||||||
|
debit_to="Debtors - _TC",
|
||||||
|
account_for_change_amount="Cash - _TC",
|
||||||
|
warehouse="Stores - _TC",
|
||||||
|
income_account="Sales - _TC",
|
||||||
|
expense_account="Cost of Goods Sold - _TC",
|
||||||
|
cost_center="Main - _TC",
|
||||||
|
item=se.get("items")[0].item_code,
|
||||||
|
rate=1000,
|
||||||
|
qty=2,
|
||||||
|
do_not_save=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
pos.get("items")[0].has_serial_no = 1
|
||||||
|
pos.get("items")[0].serial_no = serial_nos[0] + "\n" + serial_nos[0]
|
||||||
|
self.assertRaises(frappe.ValidationError, pos.submit)
|
||||||
|
|
||||||
def test_invalid_serial_no_validation(self):
|
def test_invalid_serial_no_validation(self):
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
|
||||||
|
|
||||||
|
|||||||
@@ -1153,7 +1153,7 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin):
|
|||||||
|
|
||||||
item = create_item("_Test Item for Deferred Accounting", is_purchase_item=True)
|
item = create_item("_Test Item for Deferred Accounting", is_purchase_item=True)
|
||||||
item.enable_deferred_expense = 1
|
item.enable_deferred_expense = 1
|
||||||
item.deferred_expense_account = deferred_account
|
item.item_defaults[0].deferred_expense_account = deferred_account
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
pi = make_purchase_invoice(item=item.name, qty=1, rate=100, do_not_save=True)
|
pi = make_purchase_invoice(item=item.name, qty=1, rate=100, do_not_save=True)
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ def get_data():
|
|||||||
},
|
},
|
||||||
"internal_links": {
|
"internal_links": {
|
||||||
"Sales Order": ["items", "sales_order"],
|
"Sales Order": ["items", "sales_order"],
|
||||||
"Delivery Note": ["items", "delivery_note"],
|
|
||||||
"Timesheet": ["timesheets", "time_sheet"],
|
"Timesheet": ["timesheets", "time_sheet"],
|
||||||
},
|
},
|
||||||
|
"internal_and_external_links": {
|
||||||
|
"Delivery Note": ["items", "delivery_note"],
|
||||||
|
},
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{
|
{
|
||||||
"label": _("Payment"),
|
"label": _("Payment"),
|
||||||
|
|||||||
@@ -2322,7 +2322,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
item = create_item("_Test Item for Deferred Accounting")
|
item = create_item("_Test Item for Deferred Accounting")
|
||||||
item.enable_deferred_revenue = 1
|
item.enable_deferred_revenue = 1
|
||||||
item.deferred_revenue_account = deferred_account
|
item.item_defaults[0].deferred_revenue_account = deferred_account
|
||||||
item.no_of_months = 12
|
item.no_of_months = 12
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
@@ -3102,7 +3102,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
item = create_item("_Test Item for Deferred Accounting")
|
item = create_item("_Test Item for Deferred Accounting")
|
||||||
item.enable_deferred_expense = 1
|
item.enable_deferred_expense = 1
|
||||||
item.deferred_revenue_account = deferred_account
|
item.item_defaults[0].deferred_revenue_account = deferred_account
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
si = create_sales_invoice(
|
si = create_sales_invoice(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
|
|
||||||
def test_accounts_receivable_with_supplier(self):
|
def test_accounts_payable_for_foreign_currency_supplier(self):
|
||||||
pi = self.create_purchase_invoice(do_not_submit=True)
|
pi = self.create_purchase_invoice(do_not_submit=True)
|
||||||
pi.currency = "USD"
|
pi.currency = "USD"
|
||||||
pi.conversion_rate = 80
|
pi.conversion_rate = 80
|
||||||
|
|||||||
@@ -38,32 +38,31 @@ frappe.query_reports["Accounts Receivable"] = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "customer",
|
"fieldname": "party_type",
|
||||||
"label": __("Customer"),
|
"label": __("Party Type"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Customer",
|
"options": "Party Type",
|
||||||
|
"Default": "Customer",
|
||||||
|
get_query: () => {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'account_type': 'Receivable'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
on_change: () => {
|
on_change: () => {
|
||||||
var customer = frappe.query_report.get_filter_value('customer');
|
frappe.query_report.set_filter_value('party', "");
|
||||||
var company = frappe.query_report.get_filter_value('company');
|
let party_type = frappe.query_report.get_filter_value('party_type');
|
||||||
if (customer) {
|
frappe.query_report.toggle_filter_display('customer_group', frappe.query_report.get_filter_value('party_type') !== "Customer");
|
||||||
frappe.db.get_value('Customer', customer, ["customer_name", "payment_terms"], function(value) {
|
|
||||||
frappe.query_report.set_filter_value('customer_name', value["customer_name"]);
|
|
||||||
frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company},
|
|
||||||
["credit_limit"], function(value) {
|
|
||||||
if (value) {
|
|
||||||
frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
|
|
||||||
}
|
|
||||||
}, "Customer");
|
|
||||||
} else {
|
|
||||||
frappe.query_report.set_filter_value('customer_name', "");
|
|
||||||
frappe.query_report.set_filter_value('credit_limit', "");
|
|
||||||
frappe.query_report.set_filter_value('payment_terms', "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname":"party",
|
||||||
|
"label": __("Party"),
|
||||||
|
"fieldtype": "Dynamic Link",
|
||||||
|
"options": "party_type",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "party_account",
|
"fieldname": "party_account",
|
||||||
"label": __("Receivable Account"),
|
"label": __("Receivable Account"),
|
||||||
@@ -174,24 +173,6 @@ frappe.query_reports["Accounts Receivable"] = {
|
|||||||
"fieldname": "show_remarks",
|
"fieldname": "show_remarks",
|
||||||
"label": __("Show Remarks"),
|
"label": __("Show Remarks"),
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "customer_name",
|
|
||||||
"label": __("Customer Name"),
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "payment_terms",
|
|
||||||
"label": __("Payment Tems"),
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"hidden": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "credit_limit",
|
|
||||||
"label": __("Credit Limit"),
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"hidden": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -769,15 +769,12 @@ class ReceivablePayableReport(object):
|
|||||||
self.or_filters = []
|
self.or_filters = []
|
||||||
|
|
||||||
for party_type in self.party_type:
|
for party_type in self.party_type:
|
||||||
party_type_field = scrub(party_type)
|
self.add_common_filters()
|
||||||
self.or_filters.append(self.ple.party_type == party_type)
|
|
||||||
|
|
||||||
self.add_common_filters(party_type_field=party_type_field)
|
if self.account_type == "Receivable":
|
||||||
|
|
||||||
if party_type_field == "customer":
|
|
||||||
self.add_customer_filters()
|
self.add_customer_filters()
|
||||||
|
|
||||||
elif party_type_field == "supplier":
|
elif self.account_type == "Payable":
|
||||||
self.add_supplier_filters()
|
self.add_supplier_filters()
|
||||||
|
|
||||||
if self.filters.cost_center:
|
if self.filters.cost_center:
|
||||||
@@ -793,16 +790,13 @@ class ReceivablePayableReport(object):
|
|||||||
]
|
]
|
||||||
self.qb_selection_filter.append(self.ple.cost_center.isin(cost_center_list))
|
self.qb_selection_filter.append(self.ple.cost_center.isin(cost_center_list))
|
||||||
|
|
||||||
def add_common_filters(self, party_type_field):
|
def add_common_filters(self):
|
||||||
if self.filters.company:
|
if self.filters.company:
|
||||||
self.qb_selection_filter.append(self.ple.company == self.filters.company)
|
self.qb_selection_filter.append(self.ple.company == self.filters.company)
|
||||||
|
|
||||||
if self.filters.finance_book:
|
if self.filters.finance_book:
|
||||||
self.qb_selection_filter.append(self.ple.finance_book == self.filters.finance_book)
|
self.qb_selection_filter.append(self.ple.finance_book == self.filters.finance_book)
|
||||||
|
|
||||||
if self.filters.get(party_type_field):
|
|
||||||
self.qb_selection_filter.append(self.ple.party == self.filters.get(party_type_field))
|
|
||||||
|
|
||||||
if self.filters.get("party_type"):
|
if self.filters.get("party_type"):
|
||||||
self.qb_selection_filter.append(self.filters.party_type == self.ple.party_type)
|
self.qb_selection_filter.append(self.filters.party_type == self.ple.party_type)
|
||||||
|
|
||||||
@@ -969,6 +963,20 @@ class ReceivablePayableReport(object):
|
|||||||
fieldtype="Link",
|
fieldtype="Link",
|
||||||
options="Contact",
|
options="Contact",
|
||||||
)
|
)
|
||||||
|
if self.filters.party_type == "Customer":
|
||||||
|
self.add_column(
|
||||||
|
_("Customer Name"),
|
||||||
|
fieldname="customer_name",
|
||||||
|
fieldtype="Link",
|
||||||
|
options="Customer",
|
||||||
|
)
|
||||||
|
elif self.filters.party_type == "Supplier":
|
||||||
|
self.add_column(
|
||||||
|
_("Supplier Name"),
|
||||||
|
fieldname="supplier_name",
|
||||||
|
fieldtype="Link",
|
||||||
|
options="Supplier",
|
||||||
|
)
|
||||||
|
|
||||||
self.add_column(label=_("Cost Center"), fieldname="cost_center", fieldtype="Data")
|
self.add_column(label=_("Cost Center"), fieldname="cost_center", fieldtype="Data")
|
||||||
self.add_column(label=_("Voucher Type"), fieldname="voucher_type", fieldtype="Data")
|
self.add_column(label=_("Voucher Type"), fieldname="voucher_type", fieldtype="Data")
|
||||||
|
|||||||
@@ -568,3 +568,40 @@ class TestAccountsReceivable(AccountsTestMixin, FrappeTestCase):
|
|||||||
row.account_currency,
|
row.account_currency,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_usd_customer_filter(self):
|
||||||
|
filters = {
|
||||||
|
"company": self.company,
|
||||||
|
"party_type": "Customer",
|
||||||
|
"party": self.customer,
|
||||||
|
"report_date": today(),
|
||||||
|
"range1": 30,
|
||||||
|
"range2": 60,
|
||||||
|
"range3": 90,
|
||||||
|
"range4": 120,
|
||||||
|
}
|
||||||
|
|
||||||
|
si = self.create_sales_invoice(no_payment_schedule=True, do_not_submit=True)
|
||||||
|
si.currency = "USD"
|
||||||
|
si.conversion_rate = 80
|
||||||
|
si.debit_to = self.debtors_usd
|
||||||
|
si.save().submit()
|
||||||
|
name = si.name
|
||||||
|
|
||||||
|
# check invoice grand total and invoiced column's value for 3 payment terms
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"voucher_type": si.doctype,
|
||||||
|
"voucher_no": si.name,
|
||||||
|
"party_account": self.debtors_usd,
|
||||||
|
"customer_name": self.customer,
|
||||||
|
"invoiced": 100.0,
|
||||||
|
"outstanding": 100.0,
|
||||||
|
"account_currency": "USD",
|
||||||
|
}
|
||||||
|
self.assertEqual(len(report[1]), 1)
|
||||||
|
report_output = report[1][0]
|
||||||
|
for field in expected:
|
||||||
|
with self.subTest(field=field):
|
||||||
|
self.assertEqual(report_output.get(field), expected.get(field))
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin):
|
|||||||
self.create_item("_Test Internet Subscription", 0, self.warehouse, self.company)
|
self.create_item("_Test Internet Subscription", 0, self.warehouse, self.company)
|
||||||
item = frappe.get_doc("Item", self.item)
|
item = frappe.get_doc("Item", self.item)
|
||||||
item.enable_deferred_revenue = 1
|
item.enable_deferred_revenue = 1
|
||||||
item.deferred_revenue_account = self.deferred_revenue_account
|
item.item_defaults[0].deferred_revenue_account = self.deferred_revenue_account
|
||||||
item.no_of_months = 3
|
item.no_of_months = 3
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ class TestDeferredRevenueAndExpense(FrappeTestCase, AccountsTestMixin):
|
|||||||
self.create_item("_Test Office Desk", 0, self.warehouse, self.company)
|
self.create_item("_Test Office Desk", 0, self.warehouse, self.company)
|
||||||
item = frappe.get_doc("Item", self.item)
|
item = frappe.get_doc("Item", self.item)
|
||||||
item.enable_deferred_expense = 1
|
item.enable_deferred_expense = 1
|
||||||
item.deferred_expense_account = self.deferred_expense_account
|
item.item_defaults[0].deferred_expense_account = self.deferred_expense_account
|
||||||
item.no_of_months_exp = 3
|
item.no_of_months_exp = 3
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
|
|||||||
@@ -272,20 +272,19 @@ def get_conditions(filters):
|
|||||||
if match_conditions:
|
if match_conditions:
|
||||||
conditions.append(match_conditions)
|
conditions.append(match_conditions)
|
||||||
|
|
||||||
if filters.get("include_dimensions"):
|
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
||||||
accounting_dimensions = get_accounting_dimensions(as_list=False)
|
|
||||||
|
|
||||||
if accounting_dimensions:
|
if accounting_dimensions:
|
||||||
for dimension in accounting_dimensions:
|
for dimension in accounting_dimensions:
|
||||||
if not dimension.disabled:
|
if not dimension.disabled:
|
||||||
if filters.get(dimension.fieldname):
|
if filters.get(dimension.fieldname):
|
||||||
if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"):
|
if frappe.get_cached_value("DocType", dimension.document_type, "is_tree"):
|
||||||
filters[dimension.fieldname] = get_dimension_with_children(
|
filters[dimension.fieldname] = get_dimension_with_children(
|
||||||
dimension.document_type, filters.get(dimension.fieldname)
|
dimension.document_type, filters.get(dimension.fieldname)
|
||||||
)
|
)
|
||||||
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
else:
|
else:
|
||||||
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
conditions.append("{0} in %({0})s".format(dimension.fieldname))
|
||||||
|
|
||||||
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
return "and {}".format(" and ".join(conditions)) if conditions else ""
|
||||||
|
|
||||||
|
|||||||
@@ -1171,6 +1171,7 @@
|
|||||||
"depends_on": "is_internal_supplier",
|
"depends_on": "is_internal_supplier",
|
||||||
"fieldname": "set_from_warehouse",
|
"fieldname": "set_from_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
"label": "Set From Warehouse",
|
"label": "Set From Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
@@ -1271,7 +1272,7 @@
|
|||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-05-24 11:16:41.195340",
|
"modified": "2023-09-13 16:21:07.361700",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
|||||||
@@ -878,6 +878,7 @@
|
|||||||
"depends_on": "eval:parent.is_internal_supplier",
|
"depends_on": "eval:parent.is_internal_supplier",
|
||||||
"fieldname": "from_warehouse",
|
"fieldname": "from_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
"label": "From Warehouse",
|
"label": "From Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
@@ -902,7 +903,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-11-29 16:47:41.364387",
|
"modified": "2023-09-13 16:22:40.825092",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
|||||||
@@ -195,6 +195,9 @@ class TestSupplier(FrappeTestCase):
|
|||||||
def create_supplier(**args):
|
def create_supplier(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
if not args.supplier_name:
|
||||||
|
args.supplier_name = frappe.generate_hash()
|
||||||
|
|
||||||
if frappe.db.exists("Supplier", args.supplier_name):
|
if frappe.db.exists("Supplier", args.supplier_name):
|
||||||
return frappe.get_doc("Supplier", args.supplier_name)
|
return frappe.get_doc("Supplier", args.supplier_name)
|
||||||
|
|
||||||
@@ -202,6 +205,7 @@ def create_supplier(**args):
|
|||||||
{
|
{
|
||||||
"doctype": "Supplier",
|
"doctype": "Supplier",
|
||||||
"supplier_name": args.supplier_name,
|
"supplier_name": args.supplier_name,
|
||||||
|
"default_currency": args.default_currency,
|
||||||
"supplier_group": args.supplier_group or "Services",
|
"supplier_group": args.supplier_group or "Services",
|
||||||
"supplier_type": args.supplier_type or "Company",
|
"supplier_type": args.supplier_type or "Company",
|
||||||
"tax_withholding_category": args.tax_withholding_category,
|
"tax_withholding_category": args.tax_withholding_category,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import copy
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.query_builder.functions import Coalesce, Sum
|
from frappe.query_builder.functions import Coalesce, Sum
|
||||||
from frappe.utils import date_diff, flt, getdate
|
from frappe.utils import cint, date_diff, flt, getdate
|
||||||
|
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
@@ -47,8 +47,10 @@ def get_data(filters):
|
|||||||
mr.transaction_date.as_("date"),
|
mr.transaction_date.as_("date"),
|
||||||
mr_item.schedule_date.as_("required_date"),
|
mr_item.schedule_date.as_("required_date"),
|
||||||
mr_item.item_code.as_("item_code"),
|
mr_item.item_code.as_("item_code"),
|
||||||
Sum(Coalesce(mr_item.stock_qty, 0)).as_("qty"),
|
Sum(Coalesce(mr_item.qty, 0)).as_("qty"),
|
||||||
Coalesce(mr_item.stock_uom, "").as_("uom"),
|
Sum(Coalesce(mr_item.stock_qty, 0)).as_("stock_qty"),
|
||||||
|
Coalesce(mr_item.uom, "").as_("uom"),
|
||||||
|
Coalesce(mr_item.stock_uom, "").as_("stock_uom"),
|
||||||
Sum(Coalesce(mr_item.ordered_qty, 0)).as_("ordered_qty"),
|
Sum(Coalesce(mr_item.ordered_qty, 0)).as_("ordered_qty"),
|
||||||
Sum(Coalesce(mr_item.received_qty, 0)).as_("received_qty"),
|
Sum(Coalesce(mr_item.received_qty, 0)).as_("received_qty"),
|
||||||
(Sum(Coalesce(mr_item.stock_qty, 0)) - Sum(Coalesce(mr_item.received_qty, 0))).as_(
|
(Sum(Coalesce(mr_item.stock_qty, 0)) - Sum(Coalesce(mr_item.received_qty, 0))).as_(
|
||||||
@@ -96,7 +98,7 @@ def get_conditions(filters, query, mr, mr_item):
|
|||||||
|
|
||||||
|
|
||||||
def update_qty_columns(row_to_update, data_row):
|
def update_qty_columns(row_to_update, data_row):
|
||||||
fields = ["qty", "ordered_qty", "received_qty", "qty_to_receive", "qty_to_order"]
|
fields = ["qty", "stock_qty", "ordered_qty", "received_qty", "qty_to_receive", "qty_to_order"]
|
||||||
for field in fields:
|
for field in fields:
|
||||||
row_to_update[field] += flt(data_row[field])
|
row_to_update[field] += flt(data_row[field])
|
||||||
|
|
||||||
@@ -104,16 +106,20 @@ def update_qty_columns(row_to_update, data_row):
|
|||||||
def prepare_data(data, filters):
|
def prepare_data(data, filters):
|
||||||
"""Prepare consolidated Report data and Chart data"""
|
"""Prepare consolidated Report data and Chart data"""
|
||||||
material_request_map, item_qty_map = {}, {}
|
material_request_map, item_qty_map = {}, {}
|
||||||
|
precision = cint(frappe.db.get_default("float_precision")) or 2
|
||||||
|
|
||||||
for row in data:
|
for row in data:
|
||||||
# item wise map for charts
|
# item wise map for charts
|
||||||
if not row["item_code"] in item_qty_map:
|
if not row["item_code"] in item_qty_map:
|
||||||
item_qty_map[row["item_code"]] = {
|
item_qty_map[row["item_code"]] = {
|
||||||
"qty": row["qty"],
|
"qty": flt(row["stock_qty"], precision),
|
||||||
"ordered_qty": row["ordered_qty"],
|
"stock_qty": flt(row["stock_qty"], precision),
|
||||||
"received_qty": row["received_qty"],
|
"stock_uom": row["stock_uom"],
|
||||||
"qty_to_receive": row["qty_to_receive"],
|
"uom": row["uom"],
|
||||||
"qty_to_order": row["qty_to_order"],
|
"ordered_qty": flt(row["ordered_qty"], precision),
|
||||||
|
"received_qty": flt(row["received_qty"], precision),
|
||||||
|
"qty_to_receive": flt(row["qty_to_receive"], precision),
|
||||||
|
"qty_to_order": flt(row["qty_to_order"], precision),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
item_entry = item_qty_map[row["item_code"]]
|
item_entry = item_qty_map[row["item_code"]]
|
||||||
@@ -200,21 +206,34 @@ def get_columns(filters):
|
|||||||
{"label": _("Item Name"), "fieldname": "item_name", "fieldtype": "Data", "width": 100},
|
{"label": _("Item Name"), "fieldname": "item_name", "fieldtype": "Data", "width": 100},
|
||||||
{"label": _("Description"), "fieldname": "description", "fieldtype": "Data", "width": 200},
|
{"label": _("Description"), "fieldname": "description", "fieldtype": "Data", "width": 200},
|
||||||
{
|
{
|
||||||
"label": _("Stock UOM"),
|
"label": _("UOM"),
|
||||||
"fieldname": "uom",
|
"fieldname": "uom",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"width": 100,
|
"width": 100,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": _("Stock UOM"),
|
||||||
|
"fieldname": "stock_uom",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"width": 100,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
columns.extend(
|
columns.extend(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"label": _("Stock Qty"),
|
"label": _("Qty"),
|
||||||
"fieldname": "qty",
|
"fieldname": "qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"width": 120,
|
"width": 140,
|
||||||
|
"convertible": "qty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Qty in Stock UOM"),
|
||||||
|
"fieldname": "stock_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"width": 140,
|
||||||
"convertible": "qty",
|
"convertible": "qty",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -168,7 +168,6 @@ class AccountsController(TransactionBase):
|
|||||||
self.validate_value("base_grand_total", ">=", 0)
|
self.validate_value("base_grand_total", ">=", 0)
|
||||||
|
|
||||||
validate_return(self)
|
validate_return(self)
|
||||||
self.set_total_in_words()
|
|
||||||
|
|
||||||
self.validate_all_documents_schedule()
|
self.validate_all_documents_schedule()
|
||||||
|
|
||||||
@@ -207,6 +206,8 @@ class AccountsController(TransactionBase):
|
|||||||
if self.doctype != "Material Request" and not self.ignore_pricing_rule:
|
if self.doctype != "Material Request" and not self.ignore_pricing_rule:
|
||||||
apply_pricing_rule_on_transaction(self)
|
apply_pricing_rule_on_transaction(self)
|
||||||
|
|
||||||
|
self.set_total_in_words()
|
||||||
|
|
||||||
def before_cancel(self):
|
def before_cancel(self):
|
||||||
validate_einvoice_fields(self)
|
validate_einvoice_fields(self)
|
||||||
|
|
||||||
|
|||||||
@@ -162,10 +162,13 @@ class BuyingController(SubcontractingController):
|
|||||||
purchase_doc_field = (
|
purchase_doc_field = (
|
||||||
"purchase_receipt" if self.doctype == "Purchase Receipt" else "purchase_invoice"
|
"purchase_receipt" if self.doctype == "Purchase Receipt" else "purchase_invoice"
|
||||||
)
|
)
|
||||||
not_cancelled_asset = [
|
not_cancelled_asset = []
|
||||||
d.name
|
if self.return_against:
|
||||||
for d in frappe.db.get_all("Asset", {purchase_doc_field: self.return_against, "docstatus": 1})
|
not_cancelled_asset = [
|
||||||
]
|
d.name
|
||||||
|
for d in frappe.db.get_all("Asset", {purchase_doc_field: self.return_against, "docstatus": 1})
|
||||||
|
]
|
||||||
|
|
||||||
if self.is_return and len(not_cancelled_asset):
|
if self.is_return and len(not_cancelled_asset):
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_(
|
_(
|
||||||
|
|||||||
@@ -634,7 +634,6 @@ def get_applicable_shipping_rules(party=None, quotation=None):
|
|||||||
shipping_rules = get_shipping_rules(quotation)
|
shipping_rules = get_shipping_rules(quotation)
|
||||||
|
|
||||||
if shipping_rules:
|
if shipping_rules:
|
||||||
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
|
|
||||||
# we need this in sorted order as per the position of the rule in the settings page
|
# we need this in sorted order as per the position of the rule in the settings page
|
||||||
return [[rule, rule] for rule in shipping_rules]
|
return [[rule, rule] for rule in shipping_rules]
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
frappe.ui.form.on('Loan Repayment', {
|
frappe.ui.form.on('Loan Repayment', {
|
||||||
// refresh: function(frm) {
|
// refresh: function(frm) {
|
||||||
|
|
||||||
// }
|
// },
|
||||||
|
|
||||||
|
setup: function(frm) {
|
||||||
|
if (frappe.meta.has_field("Loan Repayment", "repay_from_salary")) {
|
||||||
|
frm.add_fetch("against_loan", "repay_from_salary", "repay_from_salary");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
frm.set_query('against_loan', function() {
|
frm.set_query('against_loan', function() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ class LoanRepayment(AccountsController):
|
|||||||
if amounts.get("due_date"):
|
if amounts.get("due_date"):
|
||||||
self.due_date = amounts.get("due_date")
|
self.due_date = amounts.get("due_date")
|
||||||
|
|
||||||
|
if hasattr(self, "repay_from_salary") and hasattr(self, "payroll_payable_account"):
|
||||||
|
if self.repay_from_salary and not self.payroll_payable_account:
|
||||||
|
frappe.throw(_("Please set Payroll Payable Account in Loan Repayment"))
|
||||||
|
elif not self.repay_from_salary and self.payroll_payable_account:
|
||||||
|
self.repay_from_salary = 1
|
||||||
|
|
||||||
def check_future_entries(self):
|
def check_future_entries(self):
|
||||||
future_repayment_date = frappe.db.get_value(
|
future_repayment_date = frappe.db.get_value(
|
||||||
"Loan Repayment",
|
"Loan Repayment",
|
||||||
|
|||||||
@@ -476,6 +476,15 @@ frappe.ui.form.on("Material Request Plan Item", {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
material_request_type(frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
|
||||||
|
if (row.from_warehouse &&
|
||||||
|
row.material_request_type !== "Material Transfer") {
|
||||||
|
frappe.model.set_value(cdt, cdn, 'from_warehouse', '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ class ProductionPlan(Document):
|
|||||||
self._rename_temporary_references()
|
self._rename_temporary_references()
|
||||||
validate_uom_is_integer(self, "stock_uom", "planned_qty")
|
validate_uom_is_integer(self, "stock_uom", "planned_qty")
|
||||||
self.validate_sales_orders()
|
self.validate_sales_orders()
|
||||||
|
self.validate_material_request_type()
|
||||||
|
|
||||||
|
def validate_material_request_type(self):
|
||||||
|
for row in self.get("mr_items"):
|
||||||
|
if row.from_warehouse and row.material_request_type != "Material Transfer":
|
||||||
|
row.from_warehouse = ""
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def validate_sales_orders(self, sales_order=None):
|
def validate_sales_orders(self, sales_order=None):
|
||||||
@@ -749,7 +755,9 @@ class ProductionPlan(Document):
|
|||||||
"items",
|
"items",
|
||||||
{
|
{
|
||||||
"item_code": item.item_code,
|
"item_code": item.item_code,
|
||||||
"from_warehouse": item.from_warehouse,
|
"from_warehouse": item.from_warehouse
|
||||||
|
if material_request_type == "Material Transfer"
|
||||||
|
else None,
|
||||||
"qty": item.quantity,
|
"qty": item.quantity,
|
||||||
"schedule_date": schedule_date,
|
"schedule_date": schedule_date,
|
||||||
"warehouse": item.warehouse,
|
"warehouse": item.warehouse,
|
||||||
|
|||||||
@@ -1087,6 +1087,41 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(reserved_qty_after_mr, before_qty)
|
self.assertEqual(reserved_qty_after_mr, before_qty)
|
||||||
|
|
||||||
|
def test_from_warehouse_for_purchase_material_request(self):
|
||||||
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
from erpnext.stock.utils import get_or_make_bin
|
||||||
|
|
||||||
|
create_item("RM-TEST-123 For Purchase", valuation_rate=100)
|
||||||
|
bin_name = get_or_make_bin("RM-TEST-123 For Purchase", "_Test Warehouse - _TC")
|
||||||
|
t_warehouse = create_warehouse("_Test Store - _TC")
|
||||||
|
make_stock_entry(
|
||||||
|
item_code="Raw Material Item 1",
|
||||||
|
qty=5,
|
||||||
|
rate=100,
|
||||||
|
target=t_warehouse,
|
||||||
|
)
|
||||||
|
|
||||||
|
plan = create_production_plan(item_code="Test Production Item 1", do_not_save=1)
|
||||||
|
mr_items = get_items_for_material_requests(
|
||||||
|
plan.as_dict(), warehouses=[{"warehouse": t_warehouse}]
|
||||||
|
)
|
||||||
|
|
||||||
|
for d in mr_items:
|
||||||
|
plan.append("mr_items", d)
|
||||||
|
|
||||||
|
plan.save()
|
||||||
|
|
||||||
|
for row in plan.mr_items:
|
||||||
|
if row.material_request_type == "Material Transfer":
|
||||||
|
self.assertEqual(row.from_warehouse, t_warehouse)
|
||||||
|
|
||||||
|
row.material_request_type = "Purchase"
|
||||||
|
|
||||||
|
plan.save()
|
||||||
|
|
||||||
|
for row in plan.mr_items:
|
||||||
|
self.assertFalse(row.from_warehouse)
|
||||||
|
|
||||||
def test_skip_available_qty_for_sub_assembly_items(self):
|
def test_skip_available_qty_for_sub_assembly_items(self):
|
||||||
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||||
|
|
||||||
|
|||||||
@@ -339,5 +339,6 @@ erpnext.patches.v14_0.update_closing_balances #15-07-2023
|
|||||||
execute:frappe.defaults.clear_default("fiscal_year")
|
execute:frappe.defaults.clear_default("fiscal_year")
|
||||||
execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for_items', 0)
|
execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for_items', 0)
|
||||||
erpnext.patches.v14_0.correct_asset_value_if_je_with_workflow
|
erpnext.patches.v14_0.correct_asset_value_if_je_with_workflow
|
||||||
|
erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults
|
||||||
# below migration patch should always run last
|
# below migration patch should always run last
|
||||||
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
erpnext.patches.v14_0.migrate_gl_to_payment_ledger
|
||||||
|
|||||||
@@ -46,6 +46,17 @@ def execute():
|
|||||||
for doctype in doctypes:
|
for doctype in doctypes:
|
||||||
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
||||||
|
|
||||||
|
titles = [
|
||||||
|
"Fees",
|
||||||
|
"Student Admission",
|
||||||
|
"Grant Application",
|
||||||
|
"Chapter",
|
||||||
|
"Certification Application",
|
||||||
|
]
|
||||||
|
items = frappe.get_all("Portal Menu Item", filters=[["title", "in", titles]], pluck="name")
|
||||||
|
for item in items:
|
||||||
|
frappe.delete_doc("Portal Menu Item", item, ignore_missing=True, force=True)
|
||||||
|
|
||||||
frappe.delete_doc("Module Def", "Education", ignore_missing=True, force=True)
|
frappe.delete_doc("Module Def", "Education", ignore_missing=True, force=True)
|
||||||
|
|
||||||
click.secho(
|
click.secho(
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def execute():
|
|||||||
for card in cards:
|
for card in cards:
|
||||||
frappe.delete_doc("Number Card", card, ignore_missing=True, force=True)
|
frappe.delete_doc("Number Card", card, ignore_missing=True, force=True)
|
||||||
|
|
||||||
titles = ["Lab Test", "Prescription", "Patient Appointment"]
|
titles = ["Lab Test", "Prescription", "Patient Appointment", "Patient"]
|
||||||
items = frappe.get_all("Portal Menu Item", filters=[["title", "in", titles]], pluck="name")
|
items = frappe.get_all("Portal Menu Item", filters=[["title", "in", titles]], pluck="name")
|
||||||
for item in items:
|
for item in items:
|
||||||
frappe.delete_doc("Portal Menu Item", item, ignore_missing=True, force=True)
|
frappe.delete_doc("Portal Menu Item", item, ignore_missing=True, force=True)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
try:
|
||||||
|
item_dict = get_deferred_accounts()
|
||||||
|
add_to_item_defaults(item_dict)
|
||||||
|
except Exception:
|
||||||
|
frappe.db.rollback()
|
||||||
|
frappe.log_error("Failed to migrate deferred accounts in Item Defaults.")
|
||||||
|
|
||||||
|
|
||||||
|
def get_deferred_accounts():
|
||||||
|
item = frappe.qb.DocType("Item")
|
||||||
|
return (
|
||||||
|
frappe.qb.from_(item)
|
||||||
|
.select(item.name, item.deferred_expense_account, item.deferred_revenue_account)
|
||||||
|
.where((item.enable_deferred_expense == 1) | (item.enable_deferred_revenue == 1))
|
||||||
|
.run(as_dict=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_to_item_defaults(item_dict):
|
||||||
|
for item in item_dict:
|
||||||
|
add_company_wise_item_default(item, "deferred_expense_account")
|
||||||
|
add_company_wise_item_default(item, "deferred_revenue_account")
|
||||||
|
|
||||||
|
|
||||||
|
def add_company_wise_item_default(item, account_type):
|
||||||
|
company = frappe.get_cached_value("Account", item[account_type], "company")
|
||||||
|
if company and item[account_type]:
|
||||||
|
item_defaults = frappe.get_cached_value("Item", item["name"], "item_defaults")
|
||||||
|
for item_row in item_defaults:
|
||||||
|
if item_row.company == company:
|
||||||
|
frappe.set_value("Item Default", item_row.name, account_type, item[account_type])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
item_defaults.append({"company": company, account_type: item[account_type]})
|
||||||
|
frappe.set_value("Item", item["name"], "item_defaults", item_defaults)
|
||||||
@@ -119,19 +119,10 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
|
if(this.frm.fields_dict['items'].grid.get_field('batch_no')) {
|
||||||
this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
|
this.frm.set_query('batch_no', 'items', function(doc, cdt, cdn) {
|
||||||
return me.set_query_for_batch(doc, cdt, cdn);
|
return me.set_query_for_batch(doc, cdt, cdn);
|
||||||
});
|
});
|
||||||
|
|
||||||
let batch_field = this.frm.get_docfield('items', 'batch_no');
|
|
||||||
if (batch_field) {
|
|
||||||
batch_field.get_route_options_for_new_doc = (row) => {
|
|
||||||
return {
|
|
||||||
'item': row.doc.item_code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
@@ -196,14 +187,6 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let batch_no_field = this.frm.get_docfield("items", "batch_no");
|
|
||||||
if (batch_no_field) {
|
|
||||||
batch_no_field.get_route_options_for_new_doc = function(row) {
|
|
||||||
return {
|
|
||||||
"item": row.doc.item_code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.frm.fields_dict["items"].grid.get_field('blanket_order')) {
|
if (this.frm.fields_dict["items"].grid.get_field('blanket_order')) {
|
||||||
this.frm.set_query("blanket_order", "items", function(doc, cdt, cdn) {
|
this.frm.set_query("blanket_order", "items", function(doc, cdt, cdn) {
|
||||||
@@ -257,6 +240,17 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this.frm.fields_dict['items'].grid.get_field('batch_no')) {
|
||||||
|
let batch_field = this.frm.get_docfield('items', 'batch_no');
|
||||||
|
if (batch_field) {
|
||||||
|
batch_field.get_route_options_for_new_doc = (row) => {
|
||||||
|
return {
|
||||||
|
'item': row.doc.item_code
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is_return() {
|
is_return() {
|
||||||
|
|||||||
@@ -1998,6 +1998,61 @@ class TestSalesOrder(FrappeTestCase):
|
|||||||
self.assertEqual(len(dn.packed_items), 1)
|
self.assertEqual(len(dn.packed_items), 1)
|
||||||
self.assertEqual(dn.items[0].item_code, "_Test Product Bundle Item Partial 2")
|
self.assertEqual(dn.items[0].item_code, "_Test Product Bundle Item Partial 2")
|
||||||
|
|
||||||
|
@change_settings("Selling Settings", {"editable_bundle_item_rates": 1})
|
||||||
|
def test_expired_rate_for_packed_item(self):
|
||||||
|
bundle = "_Test Product Bundle 1"
|
||||||
|
packed_item = "_Packed Item 1"
|
||||||
|
|
||||||
|
# test Update Items with product bundle
|
||||||
|
for product_bundle in [bundle]:
|
||||||
|
if not frappe.db.exists("Item", product_bundle):
|
||||||
|
bundle_item = make_item(product_bundle, {"is_stock_item": 0})
|
||||||
|
bundle_item.append(
|
||||||
|
"item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
|
||||||
|
)
|
||||||
|
bundle_item.save(ignore_permissions=True)
|
||||||
|
|
||||||
|
for product_bundle in [packed_item]:
|
||||||
|
if not frappe.db.exists("Item", product_bundle):
|
||||||
|
make_item(product_bundle, {"is_stock_item": 0, "stock_uom": "Nos"})
|
||||||
|
|
||||||
|
make_product_bundle(bundle, [packed_item], 1)
|
||||||
|
|
||||||
|
for scenario in [
|
||||||
|
{"valid_upto": add_days(nowdate(), -1), "expected_rate": 0.0},
|
||||||
|
{"valid_upto": add_days(nowdate(), 1), "expected_rate": 111.0},
|
||||||
|
]:
|
||||||
|
with self.subTest(scenario=scenario):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Item Price",
|
||||||
|
"item_code": packed_item,
|
||||||
|
"selling": 1,
|
||||||
|
"price_list": "_Test Price List",
|
||||||
|
"valid_from": add_days(nowdate(), -1),
|
||||||
|
"valid_upto": scenario.get("valid_upto"),
|
||||||
|
"price_list_rate": 111,
|
||||||
|
}
|
||||||
|
).save()
|
||||||
|
|
||||||
|
so = frappe.new_doc("Sales Order")
|
||||||
|
so.transaction_date = nowdate()
|
||||||
|
so.delivery_date = nowdate()
|
||||||
|
so.set_warehouse = ""
|
||||||
|
so.company = "_Test Company"
|
||||||
|
so.customer = "_Test Customer"
|
||||||
|
so.currency = "INR"
|
||||||
|
so.selling_price_list = "_Test Price List"
|
||||||
|
so.append("items", {"item_code": bundle, "qty": 1})
|
||||||
|
so.save()
|
||||||
|
|
||||||
|
self.assertEqual(len(so.items), 1)
|
||||||
|
self.assertEqual(len(so.packed_items), 1)
|
||||||
|
self.assertEqual(so.items[0].item_code, bundle)
|
||||||
|
self.assertEqual(so.packed_items[0].item_code, packed_item)
|
||||||
|
self.assertEqual(so.items[0].rate, scenario.get("expected_rate"))
|
||||||
|
self.assertEqual(so.packed_items[0].rate, scenario.get("expected_rate"))
|
||||||
|
|
||||||
|
|
||||||
def automatically_fetch_payment_terms(enable=1):
|
def automatically_fetch_payment_terms(enable=1):
|
||||||
accounts_settings = frappe.get_doc("Accounts Settings")
|
accounts_settings = frappe.get_doc("Accounts Settings")
|
||||||
|
|||||||
@@ -1252,6 +1252,7 @@
|
|||||||
"depends_on": "eval: doc.is_internal_customer",
|
"depends_on": "eval: doc.is_internal_customer",
|
||||||
"fieldname": "set_target_warehouse",
|
"fieldname": "set_target_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Set Target Warehouse",
|
"label": "Set Target Warehouse",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
@@ -1399,7 +1400,7 @@
|
|||||||
"idx": 146,
|
"idx": 146,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-06-16 14:58:55.066602",
|
"modified": "2023-09-04 14:15:28.363184",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note",
|
"name": "Delivery Note",
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ class DeliveryNote(SellingController):
|
|||||||
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
self.validate_uom_is_integer("stock_uom", "stock_qty")
|
||||||
self.validate_uom_is_integer("uom", "qty")
|
self.validate_uom_is_integer("uom", "qty")
|
||||||
self.validate_with_previous_doc()
|
self.validate_with_previous_doc()
|
||||||
|
self.validate_duplicate_serial_nos()
|
||||||
|
|
||||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||||
|
|
||||||
@@ -412,6 +413,21 @@ class DeliveryNote(SellingController):
|
|||||||
pluck="name",
|
pluck="name",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_duplicate_serial_nos(self):
|
||||||
|
serial_nos = []
|
||||||
|
for item in self.items:
|
||||||
|
if not item.serial_no:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for serial_no in item.serial_no.split("\n"):
|
||||||
|
if serial_no in serial_nos:
|
||||||
|
frappe.throw(
|
||||||
|
_("Row #{0}: Serial No {1} is already selected.").format(item.idx, serial_no),
|
||||||
|
title=_("Duplicate Serial No"),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
serial_nos.append(serial_no)
|
||||||
|
|
||||||
|
|
||||||
def update_billed_amount_based_on_so(so_detail, update_modified=True):
|
def update_billed_amount_based_on_so(so_detail, update_modified=True):
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ def get_data():
|
|||||||
},
|
},
|
||||||
"internal_links": {
|
"internal_links": {
|
||||||
"Sales Order": ["items", "against_sales_order"],
|
"Sales Order": ["items", "against_sales_order"],
|
||||||
"Sales Invoice": ["items", "against_sales_invoice"],
|
|
||||||
"Material Request": ["items", "material_request"],
|
"Material Request": ["items", "material_request"],
|
||||||
"Purchase Order": ["items", "purchase_order"],
|
"Purchase Order": ["items", "purchase_order"],
|
||||||
},
|
},
|
||||||
|
"internal_and_external_links": {
|
||||||
|
"Sales Invoice": ["items", "against_sales_invoice"],
|
||||||
|
},
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{"label": _("Related"), "items": ["Sales Invoice", "Packing Slip", "Delivery Trip"]},
|
{"label": _("Related"), "items": ["Sales Invoice", "Packing Slip", "Delivery Trip"]},
|
||||||
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
|
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
|
||||||
|
|||||||
@@ -1211,6 +1211,38 @@ class TestDeliveryNote(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertTrue(return_dn.docstatus == 1)
|
self.assertTrue(return_dn.docstatus == 1)
|
||||||
|
|
||||||
|
def test_duplicate_serial_no_in_delivery_note(self):
|
||||||
|
# Step - 1: Create Serial Item
|
||||||
|
serial_item = make_item(
|
||||||
|
properties={
|
||||||
|
"is_stock_item": 1,
|
||||||
|
"has_serial_no": 1,
|
||||||
|
"serial_no_series": frappe.generate_hash("", 10) + ".###",
|
||||||
|
}
|
||||||
|
).name
|
||||||
|
|
||||||
|
# Step - 2: Inward Stock
|
||||||
|
se = make_stock_entry(item_code=serial_item, target="_Test Warehouse - _TC", qty=4)
|
||||||
|
|
||||||
|
# Step - 3: Create Delivery Note with Duplicare Serial Nos
|
||||||
|
serial_nos = se.items[0].serial_no.split("\n")
|
||||||
|
dn = create_delivery_note(
|
||||||
|
item_code=serial_item,
|
||||||
|
warehouse="_Test Warehouse - _TC",
|
||||||
|
qty=2,
|
||||||
|
do_not_save=True,
|
||||||
|
)
|
||||||
|
dn.items[0].serial_no = "\n".join(serial_nos[:2])
|
||||||
|
dn.append("items", dn.items[0].as_dict())
|
||||||
|
|
||||||
|
# Test - 1: ValidationError should be raised
|
||||||
|
self.assertRaises(frappe.ValidationError, dn.save)
|
||||||
|
|
||||||
|
# Step - 4: Submit Delivery Note with unique Serial Nos
|
||||||
|
dn.items[1].serial_no = "\n".join(serial_nos[2:])
|
||||||
|
dn.save()
|
||||||
|
dn.submit()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
|
frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
|
||||||
|
|||||||
@@ -350,18 +350,20 @@ $.extend(erpnext.item, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.fields_dict['deferred_revenue_account'].get_query = function() {
|
frm.fields_dict["item_defaults"].grid.get_field("deferred_revenue_account").get_query = function(doc, cdt, cdn) {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
|
"company": locals[cdt][cdn].company,
|
||||||
'root_type': 'Liability',
|
'root_type': 'Liability',
|
||||||
"is_group": 0
|
"is_group": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.fields_dict['deferred_expense_account'].get_query = function() {
|
frm.fields_dict["item_defaults"].grid.get_field("deferred_expense_account").get_query = function(doc, cdt, cdn) {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
|
"company": locals[cdt][cdn].company,
|
||||||
'root_type': 'Asset',
|
'root_type': 'Asset',
|
||||||
"is_group": 0
|
"is_group": 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,13 @@
|
|||||||
"variant_based_on",
|
"variant_based_on",
|
||||||
"attributes",
|
"attributes",
|
||||||
"accounting",
|
"accounting",
|
||||||
|
"deferred_accounting_section",
|
||||||
|
"enable_deferred_expense",
|
||||||
|
"no_of_months_exp",
|
||||||
|
"column_break_9s9o",
|
||||||
|
"enable_deferred_revenue",
|
||||||
|
"no_of_months",
|
||||||
|
"section_break_avcp",
|
||||||
"item_defaults",
|
"item_defaults",
|
||||||
"purchasing_tab",
|
"purchasing_tab",
|
||||||
"purchase_uom",
|
"purchase_uom",
|
||||||
@@ -85,10 +92,6 @@
|
|||||||
"delivered_by_supplier",
|
"delivered_by_supplier",
|
||||||
"column_break2",
|
"column_break2",
|
||||||
"supplier_items",
|
"supplier_items",
|
||||||
"deferred_expense_section",
|
|
||||||
"enable_deferred_expense",
|
|
||||||
"deferred_expense_account",
|
|
||||||
"no_of_months_exp",
|
|
||||||
"foreign_trade_details",
|
"foreign_trade_details",
|
||||||
"country_of_origin",
|
"country_of_origin",
|
||||||
"column_break_59",
|
"column_break_59",
|
||||||
@@ -99,10 +102,6 @@
|
|||||||
"is_sales_item",
|
"is_sales_item",
|
||||||
"column_break3",
|
"column_break3",
|
||||||
"max_discount",
|
"max_discount",
|
||||||
"deferred_revenue",
|
|
||||||
"enable_deferred_revenue",
|
|
||||||
"deferred_revenue_account",
|
|
||||||
"no_of_months",
|
|
||||||
"customer_details",
|
"customer_details",
|
||||||
"customer_items",
|
"customer_items",
|
||||||
"item_tax_section_break",
|
"item_tax_section_break",
|
||||||
@@ -657,20 +656,6 @@
|
|||||||
"oldfieldname": "max_discount",
|
"oldfieldname": "max_discount",
|
||||||
"oldfieldtype": "Currency"
|
"oldfieldtype": "Currency"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"collapsible": 1,
|
|
||||||
"fieldname": "deferred_revenue",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Deferred Revenue"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"depends_on": "enable_deferred_revenue",
|
|
||||||
"fieldname": "deferred_revenue_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"ignore_user_permissions": 1,
|
|
||||||
"label": "Deferred Revenue Account",
|
|
||||||
"options": "Account"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "enable_deferred_revenue",
|
"fieldname": "enable_deferred_revenue",
|
||||||
@@ -681,21 +666,7 @@
|
|||||||
"depends_on": "enable_deferred_revenue",
|
"depends_on": "enable_deferred_revenue",
|
||||||
"fieldname": "no_of_months",
|
"fieldname": "no_of_months",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "No of Months"
|
"label": "No of Months (Revenue)"
|
||||||
},
|
|
||||||
{
|
|
||||||
"collapsible": 1,
|
|
||||||
"fieldname": "deferred_expense_section",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Deferred Expense"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"depends_on": "enable_deferred_expense",
|
|
||||||
"fieldname": "deferred_expense_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"ignore_user_permissions": 1,
|
|
||||||
"label": "Deferred Expense Account",
|
|
||||||
"options": "Account"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@@ -904,6 +875,20 @@
|
|||||||
"fieldname": "accounting",
|
"fieldname": "accounting",
|
||||||
"fieldtype": "Tab Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Accounting"
|
"label": "Accounting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_9s9o",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_avcp",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "deferred_accounting_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Deferred Accounting"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-tag",
|
"icon": "fa fa-tag",
|
||||||
@@ -912,7 +897,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"make_attachments_public": 1,
|
"make_attachments_public": 1,
|
||||||
"modified": "2023-07-14 17:18:18.658942",
|
"modified": "2023-09-11 13:46:32.688051",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item",
|
"name": "Item",
|
||||||
|
|||||||
@@ -19,7 +19,11 @@
|
|||||||
"selling_defaults",
|
"selling_defaults",
|
||||||
"selling_cost_center",
|
"selling_cost_center",
|
||||||
"column_break_12",
|
"column_break_12",
|
||||||
"income_account"
|
"income_account",
|
||||||
|
"deferred_accounting_defaults_section",
|
||||||
|
"deferred_expense_account",
|
||||||
|
"column_break_kwad",
|
||||||
|
"deferred_revenue_account"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -108,11 +112,34 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Default Provisional Account",
|
"label": "Default Provisional Account",
|
||||||
"options": "Account"
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "deferred_accounting_defaults_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Deferred Accounting Defaults"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: parent.enable_deferred_expense",
|
||||||
|
"fieldname": "deferred_expense_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Deferred Expense Account",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval: parent.enable_deferred_revenue",
|
||||||
|
"fieldname": "deferred_revenue_account",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Deferred Revenue Account",
|
||||||
|
"options": "Account"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_kwad",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-10 20:18:54.148195",
|
"modified": "2023-09-04 12:33:14.607267",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Default",
|
"name": "Item Default",
|
||||||
|
|||||||
@@ -296,6 +296,7 @@
|
|||||||
"depends_on": "eval:doc.material_request_type == 'Material Transfer'",
|
"depends_on": "eval:doc.material_request_type == 'Material Transfer'",
|
||||||
"fieldname": "set_from_warehouse",
|
"fieldname": "set_from_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"ignore_user_permissions": 1,
|
||||||
"label": "Set Source Warehouse",
|
"label": "Set Source Warehouse",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
@@ -356,7 +357,7 @@
|
|||||||
"idx": 70,
|
"idx": 70,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-07-25 17:19:31.662662",
|
"modified": "2023-09-15 12:07:24.789471",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Material Request",
|
"name": "Material Request",
|
||||||
|
|||||||
@@ -207,6 +207,9 @@ def update_packed_item_price_data(pi_row, item_data, doc):
|
|||||||
"conversion_rate": doc.get("conversion_rate"),
|
"conversion_rate": doc.get("conversion_rate"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
if not row_data.get("transaction_date"):
|
||||||
|
row_data.update({"transaction_date": doc.get("transaction_date")})
|
||||||
|
|
||||||
rate = get_price_list_rate(row_data, item_doc).get("price_list_rate")
|
rate = get_price_list_rate(row_data, item_doc).get("price_list_rate")
|
||||||
|
|
||||||
pi_row.rate = rate or item_data.get("valuation_rate") or 0.0
|
pi_row.rate = rate or item_data.get("valuation_rate") or 0.0
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
account=provisional_account,
|
account=provisional_account,
|
||||||
cost_center=item.cost_center,
|
cost_center=item.cost_center,
|
||||||
debit=0.0,
|
debit=0.0,
|
||||||
credit=multiplication_factor * item.amount,
|
credit=multiplication_factor * item.base_amount,
|
||||||
remarks=remarks,
|
remarks=remarks,
|
||||||
against_account=expense_account,
|
against_account=expense_account,
|
||||||
account_currency=credit_currency,
|
account_currency=credit_currency,
|
||||||
@@ -619,7 +619,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
gl_entries=gl_entries,
|
gl_entries=gl_entries,
|
||||||
account=expense_account,
|
account=expense_account,
|
||||||
cost_center=item.cost_center,
|
cost_center=item.cost_center,
|
||||||
debit=multiplication_factor * item.amount,
|
debit=multiplication_factor * item.base_amount,
|
||||||
credit=0.0,
|
credit=0.0,
|
||||||
remarks=remarks,
|
remarks=remarks,
|
||||||
against_account=provisional_account,
|
against_account=provisional_account,
|
||||||
|
|||||||
@@ -2024,6 +2024,49 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
ste7.reload()
|
ste7.reload()
|
||||||
self.assertEqual(ste7.items[0].valuation_rate, valuation_rate)
|
self.assertEqual(ste7.items[0].valuation_rate, valuation_rate)
|
||||||
|
|
||||||
|
def test_purchase_receipt_provisional_accounting(self):
|
||||||
|
# Step - 1: Create Supplier with Default Currency as USD
|
||||||
|
from erpnext.buying.doctype.supplier.test_supplier import create_supplier
|
||||||
|
|
||||||
|
supplier = create_supplier(default_currency="USD")
|
||||||
|
|
||||||
|
# Step - 2: Setup Company for Provisional Accounting
|
||||||
|
from erpnext.accounts.doctype.account.test_account import create_account
|
||||||
|
|
||||||
|
provisional_account = create_account(
|
||||||
|
account_name="Provision Account",
|
||||||
|
parent_account="Current Liabilities - _TC",
|
||||||
|
company="_Test Company",
|
||||||
|
)
|
||||||
|
company = frappe.get_doc("Company", "_Test Company")
|
||||||
|
company.enable_provisional_accounting_for_non_stock_items = 1
|
||||||
|
company.default_provisional_account = provisional_account
|
||||||
|
company.save()
|
||||||
|
|
||||||
|
# Step - 3: Create Non-Stock Item
|
||||||
|
item = make_item(properties={"is_stock_item": 0})
|
||||||
|
|
||||||
|
# Step - 4: Create Purchase Receipt
|
||||||
|
pr = make_purchase_receipt(
|
||||||
|
qty=2,
|
||||||
|
item_code=item.name,
|
||||||
|
company=company.name,
|
||||||
|
supplier=supplier.name,
|
||||||
|
currency=supplier.default_currency,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test - 1: Total and Base Total should not be the same as the currency is different
|
||||||
|
self.assertNotEqual(flt(pr.total, 2), flt(pr.base_total, 2))
|
||||||
|
self.assertEqual(flt(pr.total * pr.conversion_rate, 2), flt(pr.base_total, 2))
|
||||||
|
|
||||||
|
# Test - 2: Sum of Debit or Credit should be equal to Purchase Receipt Base Total
|
||||||
|
amount = frappe.db.get_value("GL Entry", {"docstatus": 1, "voucher_no": pr.name}, ["sum(debit)"])
|
||||||
|
expected_amount = pr.base_total
|
||||||
|
self.assertEqual(amount, expected_amount)
|
||||||
|
|
||||||
|
company.enable_provisional_accounting_for_non_stock_items = 0
|
||||||
|
company.save()
|
||||||
|
|
||||||
|
|
||||||
def prepare_data_for_internal_transfer():
|
def prepare_data_for_internal_transfer():
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
||||||
|
|||||||
@@ -101,15 +101,6 @@ frappe.ui.form.on('Stock Entry', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let batch_field = frm.get_docfield('items', 'batch_no');
|
|
||||||
if (batch_field) {
|
|
||||||
batch_field.get_route_options_for_new_doc = (row) => {
|
|
||||||
return {
|
|
||||||
'item': row.doc.item_code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
|
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
|
||||||
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
|
||||||
|
|
||||||
@@ -345,6 +336,15 @@ frappe.ui.form.on('Stock Entry', {
|
|||||||
if(!check_should_not_attach_bom_items(frm.doc.bom_no)) {
|
if(!check_should_not_attach_bom_items(frm.doc.bom_no)) {
|
||||||
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let batch_field = frm.get_docfield('items', 'batch_no');
|
||||||
|
if (batch_field) {
|
||||||
|
batch_field.get_route_options_for_new_doc = (row) => {
|
||||||
|
return {
|
||||||
|
'item': row.doc.item_code
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get_items_from_transit_entry: function(frm) {
|
get_items_from_transit_entry: function(frm) {
|
||||||
|
|||||||
@@ -729,7 +729,11 @@ def get_default_discount_account(args, item):
|
|||||||
def get_default_deferred_account(args, item, fieldname=None):
|
def get_default_deferred_account(args, item, fieldname=None):
|
||||||
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
|
||||||
return (
|
return (
|
||||||
item.get(fieldname)
|
frappe.get_cached_value(
|
||||||
|
"Item Default",
|
||||||
|
{"parent": args.item_code, "company": args.get("company")},
|
||||||
|
fieldname,
|
||||||
|
)
|
||||||
or args.get(fieldname)
|
or args.get(fieldname)
|
||||||
or frappe.get_cached_value("Company", args.company, "default_" + fieldname)
|
or frappe.get_cached_value("Company", args.company, "default_" + fieldname)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,23 +3,23 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
const DIFFERNCE_FIELD_NAMES = [
|
const DIFFERNCE_FIELD_NAMES = [
|
||||||
"difference_in_qty",
|
'difference_in_qty',
|
||||||
"fifo_qty_diff",
|
'fifo_qty_diff',
|
||||||
"fifo_value_diff",
|
'fifo_value_diff',
|
||||||
"fifo_valuation_diff",
|
'fifo_valuation_diff',
|
||||||
"valuation_diff",
|
'valuation_diff',
|
||||||
"fifo_difference_diff",
|
'fifo_difference_diff',
|
||||||
"diff_value_diff"
|
'diff_value_diff'
|
||||||
];
|
];
|
||||||
|
|
||||||
frappe.query_reports["Stock Ledger Invariant Check"] = {
|
frappe.query_reports['Stock Ledger Invariant Check'] = {
|
||||||
"filters": [
|
'filters': [
|
||||||
{
|
{
|
||||||
"fieldname": "item_code",
|
'fieldname': 'item_code',
|
||||||
"fieldtype": "Link",
|
'fieldtype': 'Link',
|
||||||
"label": "Item",
|
'label': 'Item',
|
||||||
"mandatory": 1,
|
'mandatory': 1,
|
||||||
"options": "Item",
|
'options': 'Item',
|
||||||
get_query: function() {
|
get_query: function() {
|
||||||
return {
|
return {
|
||||||
filters: {is_stock_item: 1, has_serial_no: 0}
|
filters: {is_stock_item: 1, has_serial_no: 0}
|
||||||
@@ -27,18 +27,61 @@ frappe.query_reports["Stock Ledger Invariant Check"] = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "warehouse",
|
'fieldname': 'warehouse',
|
||||||
"fieldtype": "Link",
|
'fieldtype': 'Link',
|
||||||
"label": "Warehouse",
|
'label': 'Warehouse',
|
||||||
"mandatory": 1,
|
'mandatory': 1,
|
||||||
"options": "Warehouse",
|
'options': 'Warehouse',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
formatter (value, row, column, data, default_formatter) {
|
formatter (value, row, column, data, default_formatter) {
|
||||||
value = default_formatter(value, row, column, data);
|
value = default_formatter(value, row, column, data);
|
||||||
if (DIFFERNCE_FIELD_NAMES.includes(column.fieldname) && Math.abs(data[column.fieldname]) > 0.001) {
|
if (DIFFERNCE_FIELD_NAMES.includes(column.fieldname) && Math.abs(data[column.fieldname]) > 0.001) {
|
||||||
value = "<span style='color:red'>" + value + "</span>";
|
value = '<span style="color:red">' + value + '</span>';
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get_datatable_options(options) {
|
||||||
|
return Object.assign(options, {
|
||||||
|
checkboxColumn: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onload(report) {
|
||||||
|
report.page.add_inner_button(__('Create Reposting Entry'), () => {
|
||||||
|
let message = `
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Reposting Entry will change the value of
|
||||||
|
accounts Stock In Hand, and Stock Expenses
|
||||||
|
in the Trial Balance report and will also change
|
||||||
|
the Balance Value in the Stock Balance report.
|
||||||
|
</p>
|
||||||
|
<p>Are you sure you want to create a Reposting Entry?</p>
|
||||||
|
</div>`;
|
||||||
|
let indexes = frappe.query_report.datatable.rowmanager.getCheckedRows();
|
||||||
|
let selected_rows = indexes.map(i => frappe.query_report.data[i]);
|
||||||
|
|
||||||
|
if (!selected_rows.length) {
|
||||||
|
frappe.throw(__('Please select a row to create a Reposting Entry'));
|
||||||
|
}
|
||||||
|
else if (selected_rows.length > 1) {
|
||||||
|
frappe.throw(__('Please select only one row to create a Reposting Entry'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frappe.confirm(__(message), () => {
|
||||||
|
frappe.call({
|
||||||
|
method: 'erpnext.stock.report.stock_ledger_invariant_check.stock_ledger_invariant_check.create_reposting_entries',
|
||||||
|
args: {
|
||||||
|
rows: selected_rows,
|
||||||
|
item_code: frappe.query_report.get_filter_values().item_code,
|
||||||
|
warehouse: frappe.query_report.get_filter_values().warehouse,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import json
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import get_link_to_form, parse_json
|
||||||
|
|
||||||
SLE_FIELDS = (
|
SLE_FIELDS = (
|
||||||
"name",
|
"name",
|
||||||
@@ -258,3 +259,35 @@ def get_columns():
|
|||||||
"label": _("H - J"),
|
"label": _("H - J"),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def create_reposting_entries(rows, item_code=None, warehouse=None):
|
||||||
|
if isinstance(rows, str):
|
||||||
|
rows = parse_json(rows)
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for row in rows:
|
||||||
|
row = frappe._dict(row)
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Repost Item Valuation",
|
||||||
|
"based_on": "Item and Warehouse",
|
||||||
|
"status": "Queued",
|
||||||
|
"item_code": item_code or row.item_code,
|
||||||
|
"warehouse": warehouse or row.warehouse,
|
||||||
|
"posting_date": row.posting_date,
|
||||||
|
"posting_time": row.posting_time,
|
||||||
|
"allow_nagative_stock": 1,
|
||||||
|
}
|
||||||
|
).submit()
|
||||||
|
|
||||||
|
entries.append(get_link_to_form("Repost Item Valuation", doc.name))
|
||||||
|
except frappe.DuplicateEntryError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if entries:
|
||||||
|
entries = ", ".join(entries)
|
||||||
|
frappe.msgprint(_("Reposting entries created: {0}").format(entries))
|
||||||
|
|||||||
@@ -75,15 +75,6 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let batch_no_field = frm.get_docfield('items', 'batch_no');
|
|
||||||
if (batch_no_field) {
|
|
||||||
batch_no_field.get_route_options_for_new_doc = function(row) {
|
|
||||||
return {
|
|
||||||
'item': row.doc.item_code
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: (frm) => {
|
refresh: (frm) => {
|
||||||
@@ -148,6 +139,15 @@ frappe.ui.form.on('Subcontracting Receipt', {
|
|||||||
|
|
||||||
frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', frm.doc.__onload && frm.doc.__onload.backflush_based_on === 'BOM');
|
frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', frm.doc.__onload && frm.doc.__onload.backflush_based_on === 'BOM');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let batch_no_field = frm.get_docfield('items', 'batch_no');
|
||||||
|
if (batch_no_field) {
|
||||||
|
batch_no_field.get_route_options_for_new_doc = function(row) {
|
||||||
|
return {
|
||||||
|
'item': row.doc.item_code
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
set_warehouse: (frm) => {
|
set_warehouse: (frm) => {
|
||||||
@@ -202,4 +202,4 @@ let set_missing_values = (frm) => {
|
|||||||
if (!r.exc) frm.refresh();
|
if (!r.exc) frm.refresh();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ Add Customers,Ajouter des clients,
|
|||||||
Add Employees,Ajouter des employés,
|
Add Employees,Ajouter des employés,
|
||||||
Add Item,Ajouter un Article,
|
Add Item,Ajouter un Article,
|
||||||
Add Items,Ajouter des articles,
|
Add Items,Ajouter des articles,
|
||||||
Add Leads,Créer des Prospects,
|
Add Leads,Créer des Leads,
|
||||||
Add Multiple Tasks,Ajouter plusieurs tâches,
|
Add Multiple Tasks,Ajouter plusieurs tâches,
|
||||||
Add Row,Ajouter une Ligne,
|
Add Row,Ajouter une Ligne,
|
||||||
Add Sales Partners,Ajouter des partenaires commerciaux,
|
Add Sales Partners,Ajouter des partenaires commerciaux,
|
||||||
@@ -658,8 +658,8 @@ Create Invoice,Créer une facture,
|
|||||||
Create Invoices,Créer des factures,
|
Create Invoices,Créer des factures,
|
||||||
Create Job Card,Créer une carte de travail,
|
Create Job Card,Créer une carte de travail,
|
||||||
Create Journal Entry,Créer une entrée de journal,
|
Create Journal Entry,Créer une entrée de journal,
|
||||||
Create Lead,Créer un Prospect,
|
Create Lead,Créer un Lead,
|
||||||
Create Leads,Créer des Prospects,
|
Create Leads,Créer des Lead,
|
||||||
Create Maintenance Visit,Créer une visite de maintenance,
|
Create Maintenance Visit,Créer une visite de maintenance,
|
||||||
Create Material Request,Créer une demande de matériel,
|
Create Material Request,Créer une demande de matériel,
|
||||||
Create Multiple,Créer plusieurs,
|
Create Multiple,Créer plusieurs,
|
||||||
@@ -951,7 +951,7 @@ End time cannot be before start time,L'heure de fin ne peut pas être avant l'he
|
|||||||
Ends On date cannot be before Next Contact Date.,La date de fin ne peut pas être avant la prochaine date de contact,
|
Ends On date cannot be before Next Contact Date.,La date de fin ne peut pas être avant la prochaine date de contact,
|
||||||
Energy,Énergie,
|
Energy,Énergie,
|
||||||
Engineer,Ingénieur,
|
Engineer,Ingénieur,
|
||||||
Enough Parts to Build,Pièces Suffisantes pour Construire
|
Enough Parts to Build,Pièces Suffisantes pour Construire,
|
||||||
Enroll,Inscrire,
|
Enroll,Inscrire,
|
||||||
Enrolling student,Inscrire un étudiant,
|
Enrolling student,Inscrire un étudiant,
|
||||||
Enrolling students,Inscription des étudiants,
|
Enrolling students,Inscription des étudiants,
|
||||||
@@ -1426,13 +1426,12 @@ Last Purchase Price,Dernier prix d'achat,
|
|||||||
Last Purchase Rate,Dernier Prix d'Achat,
|
Last Purchase Rate,Dernier Prix d'Achat,
|
||||||
Latest,Dernier,
|
Latest,Dernier,
|
||||||
Latest price updated in all BOMs,Prix les plus récents mis à jour dans toutes les nomenclatures,
|
Latest price updated in all BOMs,Prix les plus récents mis à jour dans toutes les nomenclatures,
|
||||||
Lead,Prospect,
|
Lead Count,Nombre de Lead,
|
||||||
Lead Count,Nombre de Prospects,
|
|
||||||
Lead Owner,Responsable du Prospect,
|
Lead Owner,Responsable du Prospect,
|
||||||
Lead Owner cannot be same as the Lead,Le Responsable du Prospect ne peut pas être identique au Prospect,
|
Lead Owner cannot be same as the Lead,Le Responsable du Prospect ne peut pas être identique au Lead,
|
||||||
Lead Time Days,Jours de Délai,
|
Lead Time Days,Jours de Délai,
|
||||||
Lead to Quotation,Du Prospect au Devis,
|
Lead to Quotation,Du Prospect au Devis,
|
||||||
"Leads help you get business, add all your contacts and more as your leads","Les prospects vous aident à obtenir des contrats, ajoutez tous vos contacts et plus dans votre liste de prospects",
|
"Leads help you get business, add all your contacts and more as your leads","Les lead vous aident à obtenir des contrats, ajoutez tous vos contacts et plus dans votre liste de lead",
|
||||||
Learn,Apprendre,
|
Learn,Apprendre,
|
||||||
Leave Approval Notification,Notification d'approbation de congés,
|
Leave Approval Notification,Notification d'approbation de congés,
|
||||||
Leave Blocked,Laisser Verrouillé,
|
Leave Blocked,Laisser Verrouillé,
|
||||||
@@ -1596,7 +1595,7 @@ Middle Name,Deuxième Nom,
|
|||||||
Middle Name (Optional),Deuxième Prénom (Optionnel),
|
Middle Name (Optional),Deuxième Prénom (Optionnel),
|
||||||
Min Amt can not be greater than Max Amt,Min Amt ne peut pas être supérieur à Max Amt,
|
Min Amt can not be greater than Max Amt,Min Amt ne peut pas être supérieur à Max Amt,
|
||||||
Min Qty can not be greater than Max Qty,Qté Min ne peut pas être supérieure à Qté Max,
|
Min Qty can not be greater than Max Qty,Qté Min ne peut pas être supérieure à Qté Max,
|
||||||
Minimum Lead Age (Days),Âge Minimum du Prospect (Jours),
|
Minimum Lead Age (Days),Âge Minimum du lead (Jours),
|
||||||
Miscellaneous Expenses,Charges Diverses,
|
Miscellaneous Expenses,Charges Diverses,
|
||||||
Missing Currency Exchange Rates for {0},Taux de Change Manquant pour {0},
|
Missing Currency Exchange Rates for {0},Taux de Change Manquant pour {0},
|
||||||
Missing email template for dispatch. Please set one in Delivery Settings.,Modèle de courrier électronique manquant pour l'envoi. Veuillez en définir un dans les paramètres de livraison.,
|
Missing email template for dispatch. Please set one in Delivery Settings.,Modèle de courrier électronique manquant pour l'envoi. Veuillez en définir un dans les paramètres de livraison.,
|
||||||
@@ -1676,7 +1675,7 @@ New {0} pricing rules are created,De nouvelles règles de tarification {0} sont
|
|||||||
Newsletters,Newsletters,
|
Newsletters,Newsletters,
|
||||||
Newspaper Publishers,Éditeurs de journaux,
|
Newspaper Publishers,Éditeurs de journaux,
|
||||||
Next,Suivant,
|
Next,Suivant,
|
||||||
Next Contact By cannot be same as the Lead Email Address,Prochain Contact Par ne peut être identique à l’Adresse Email du Prospect,
|
Next Contact By cannot be same as the Lead Email Address,Prochain Contact Par ne peut être identique à l’Adresse Email du Lead,
|
||||||
Next Contact Date cannot be in the past,La Date de Prochain Contact ne peut pas être dans le passé,
|
Next Contact Date cannot be in the past,La Date de Prochain Contact ne peut pas être dans le passé,
|
||||||
Next Steps,Prochaines étapes,
|
Next Steps,Prochaines étapes,
|
||||||
No Action,Pas d'action,
|
No Action,Pas d'action,
|
||||||
@@ -1808,9 +1807,9 @@ Operation Time must be greater than 0 for Operation {0},Temps de l'Opération do
|
|||||||
Operations,Opérations,
|
Operations,Opérations,
|
||||||
Operations cannot be left blank,Les opérations ne peuvent pas être laissées vides,
|
Operations cannot be left blank,Les opérations ne peuvent pas être laissées vides,
|
||||||
Opp Count,Compte d'Opportunités,
|
Opp Count,Compte d'Opportunités,
|
||||||
Opp/Lead %,Opp / Prospect %,
|
Opp/Lead %,Opp / Lead %,
|
||||||
Opportunities,Opportunités,
|
Opportunities,Opportunités,
|
||||||
Opportunities by lead source,Opportunités par source de plomb,
|
Opportunities by lead source,Opportunités par source de lead,
|
||||||
Opportunity,Opportunité,
|
Opportunity,Opportunité,
|
||||||
Opportunity Amount,Montant de l'opportunité,
|
Opportunity Amount,Montant de l'opportunité,
|
||||||
Optional Holiday List not set for leave period {0},Une liste de vacances facultative n'est pas définie pour la période de congé {0},
|
Optional Holiday List not set for leave period {0},Une liste de vacances facultative n'est pas définie pour la période de congé {0},
|
||||||
@@ -2007,7 +2006,7 @@ Please mention Basic and HRA component in Company,Veuillez mentionner les compos
|
|||||||
Please mention Round Off Account in Company,Veuillez indiquer le Compte d’Arrondi de la Société,
|
Please mention Round Off Account in Company,Veuillez indiquer le Compte d’Arrondi de la Société,
|
||||||
Please mention Round Off Cost Center in Company,Veuillez indiquer le Centre de Coûts d’Arrondi de la Société,
|
Please mention Round Off Cost Center in Company,Veuillez indiquer le Centre de Coûts d’Arrondi de la Société,
|
||||||
Please mention no of visits required,Veuillez indiquer le nb de visites requises,
|
Please mention no of visits required,Veuillez indiquer le nb de visites requises,
|
||||||
Please mention the Lead Name in Lead {0},Veuillez mentionner le nom du Prospect dans le Prospect {0},
|
Please mention the Lead Name in Lead {0},Veuillez mentionner le nom du Lead dans le Lead {0},
|
||||||
Please pull items from Delivery Note,Veuillez récupérer les articles des Bons de Livraison,
|
Please pull items from Delivery Note,Veuillez récupérer les articles des Bons de Livraison,
|
||||||
Please register the SIREN number in the company information file,Veuillez enregistrer le numéro SIREN dans la fiche d'information de la société,
|
Please register the SIREN number in the company information file,Veuillez enregistrer le numéro SIREN dans la fiche d'information de la société,
|
||||||
Please remove this Invoice {0} from C-Form {1},Veuillez retirez cette Facture {0} du C-Form {1},
|
Please remove this Invoice {0} from C-Form {1},Veuillez retirez cette Facture {0} du C-Form {1},
|
||||||
@@ -2277,7 +2276,7 @@ Queued for replacing the BOM. It may take a few minutes.,En file d'attente pour
|
|||||||
Queued for updating latest price in all Bill of Materials. It may take a few minutes.,Mise à jour des prix les plus récents dans toutes les nomenclatures en file d'attente. Cela peut prendre quelques minutes.,
|
Queued for updating latest price in all Bill of Materials. It may take a few minutes.,Mise à jour des prix les plus récents dans toutes les nomenclatures en file d'attente. Cela peut prendre quelques minutes.,
|
||||||
Quick Journal Entry,Écriture Rapide dans le Journal,
|
Quick Journal Entry,Écriture Rapide dans le Journal,
|
||||||
Quot Count,Compte de Devis,
|
Quot Count,Compte de Devis,
|
||||||
Quot/Lead %,Devis / Prospects %,
|
Quot/Lead %,Devis / Lead %,
|
||||||
Quotation,Devis,
|
Quotation,Devis,
|
||||||
Quotation {0} is cancelled,Devis {0} est annulée,
|
Quotation {0} is cancelled,Devis {0} est annulée,
|
||||||
Quotation {0} not of type {1},Le devis {0} n'est pas du type {1},
|
Quotation {0} not of type {1},Le devis {0} n'est pas du type {1},
|
||||||
@@ -2285,7 +2284,7 @@ Quotations,Devis,
|
|||||||
"Quotations are proposals, bids you have sent to your customers","Les devis sont des propositions, offres que vous avez envoyées à vos clients",
|
"Quotations are proposals, bids you have sent to your customers","Les devis sont des propositions, offres que vous avez envoyées à vos clients",
|
||||||
Quotations received from Suppliers.,Devis reçus des Fournisseurs.,
|
Quotations received from Suppliers.,Devis reçus des Fournisseurs.,
|
||||||
Quotations: ,Devis :,
|
Quotations: ,Devis :,
|
||||||
Quotes to Leads or Customers.,Devis de Prospects ou Clients.,
|
Quotes to Leads or Customers.,Devis de Lead ou Clients.,
|
||||||
RFQs are not allowed for {0} due to a scorecard standing of {1},Les Appels d'Offres ne sont pas autorisés pour {0} en raison d'une note de {1} sur la fiche d'évaluation,
|
RFQs are not allowed for {0} due to a scorecard standing of {1},Les Appels d'Offres ne sont pas autorisés pour {0} en raison d'une note de {1} sur la fiche d'évaluation,
|
||||||
Range,Plage,
|
Range,Plage,
|
||||||
Rate,Prix,
|
Rate,Prix,
|
||||||
@@ -2888,7 +2887,7 @@ Supplies made to UIN holders,Fournitures faites aux titulaires de l'UIN,
|
|||||||
Supplies made to Unregistered Persons,Fournitures faites à des personnes non inscrites,
|
Supplies made to Unregistered Persons,Fournitures faites à des personnes non inscrites,
|
||||||
Suppliies made to Composition Taxable Persons,Suppleies à des personnes assujetties à la composition,
|
Suppliies made to Composition Taxable Persons,Suppleies à des personnes assujetties à la composition,
|
||||||
Supply Type,Type d'approvisionnement,
|
Supply Type,Type d'approvisionnement,
|
||||||
Support,"Assistance/Support",
|
Support,Assistance/Support,
|
||||||
Support Analytics,Analyse de l'assistance,
|
Support Analytics,Analyse de l'assistance,
|
||||||
Support Settings,Paramètres du module Assistance,
|
Support Settings,Paramètres du module Assistance,
|
||||||
Support Tickets,Ticket d'assistance,
|
Support Tickets,Ticket d'assistance,
|
||||||
@@ -3037,7 +3036,7 @@ To Date must be greater than From Date,La date de fin doit être supérieure à
|
|||||||
To Date should be within the Fiscal Year. Assuming To Date = {0},La Date Finale doit être dans l'exercice. En supposant Date Finale = {0},
|
To Date should be within the Fiscal Year. Assuming To Date = {0},La Date Finale doit être dans l'exercice. En supposant Date Finale = {0},
|
||||||
To Datetime,À la Date,
|
To Datetime,À la Date,
|
||||||
To Deliver,À Livrer,
|
To Deliver,À Livrer,
|
||||||
{} To Deliver,{} à livrer
|
{} To Deliver,{} à livrer,
|
||||||
To Deliver and Bill,À Livrer et Facturer,
|
To Deliver and Bill,À Livrer et Facturer,
|
||||||
To Fiscal Year,À l'année fiscale,
|
To Fiscal Year,À l'année fiscale,
|
||||||
To GSTIN,GSTIN (Destination),
|
To GSTIN,GSTIN (Destination),
|
||||||
@@ -3122,7 +3121,7 @@ Total(Amt),Total (Mnt),
|
|||||||
Total(Qty),Total (Qté),
|
Total(Qty),Total (Qté),
|
||||||
Traceability,Traçabilité,
|
Traceability,Traçabilité,
|
||||||
Traceback,Retraçage,
|
Traceback,Retraçage,
|
||||||
Track Leads by Lead Source.,Suivre les prospects par sources,
|
Track Leads by Lead Source.,Suivre les leads par sources,
|
||||||
Training,Formation,
|
Training,Formation,
|
||||||
Training Event,Événement de formation,
|
Training Event,Événement de formation,
|
||||||
Training Events,Événements de formation,
|
Training Events,Événements de formation,
|
||||||
@@ -3243,8 +3242,8 @@ View Chart of Accounts,Voir le plan comptable,
|
|||||||
View Fees Records,Voir les honoraires,
|
View Fees Records,Voir les honoraires,
|
||||||
View Form,Voir le formulaire,
|
View Form,Voir le formulaire,
|
||||||
View Lab Tests,Afficher les tests de laboratoire,
|
View Lab Tests,Afficher les tests de laboratoire,
|
||||||
View Leads,Voir Prospects,
|
View Leads,Voir Lead,
|
||||||
View Ledger,Voir le Livre,
|
View Ledger,Voir le Journal,
|
||||||
View Now,Voir maintenant,
|
View Now,Voir maintenant,
|
||||||
View a list of all the help videos,Afficher la liste de toutes les vidéos d'aide,
|
View a list of all the help videos,Afficher la liste de toutes les vidéos d'aide,
|
||||||
View in Cart,Voir Panier,
|
View in Cart,Voir Panier,
|
||||||
@@ -3677,7 +3676,7 @@ Couldn't Set Service Level Agreement {0}.,Impossible de définir le contrat de s
|
|||||||
Country,Pays,
|
Country,Pays,
|
||||||
Country Code in File does not match with country code set up in the system,Le code de pays dans le fichier ne correspond pas au code de pays configuré dans le système,
|
Country Code in File does not match with country code set up in the system,Le code de pays dans le fichier ne correspond pas au code de pays configuré dans le système,
|
||||||
Create New Contact,Créer un nouveau contact,
|
Create New Contact,Créer un nouveau contact,
|
||||||
Create New Lead,Créer une nouvelle piste,
|
Create New Lead,Créer une nouvelle lead,
|
||||||
Create Pick List,Créer une liste de choix,
|
Create Pick List,Créer une liste de choix,
|
||||||
Create Quality Inspection for Item {0},Créer un contrôle qualité pour l'article {0},
|
Create Quality Inspection for Item {0},Créer un contrôle qualité pour l'article {0},
|
||||||
Creating Accounts...,Création de comptes ...,
|
Creating Accounts...,Création de comptes ...,
|
||||||
@@ -3784,7 +3783,7 @@ Group Warehouses cannot be used in transactions. Please change the value of {0},
|
|||||||
Help,Aidez-moi,
|
Help,Aidez-moi,
|
||||||
Help Article,Article d’Aide,
|
Help Article,Article d’Aide,
|
||||||
"Helps you keep tracks of Contracts based on Supplier, Customer and Employee","Vous aide à garder une trace des contrats en fonction du fournisseur, client et employé",
|
"Helps you keep tracks of Contracts based on Supplier, Customer and Employee","Vous aide à garder une trace des contrats en fonction du fournisseur, client et employé",
|
||||||
Helps you manage appointments with your leads,Vous aide à gérer les rendez-vous avec vos prospects,
|
Helps you manage appointments with your leads,Vous aide à gérer les rendez-vous avec vos leads,
|
||||||
Home,Accueil,
|
Home,Accueil,
|
||||||
IBAN is not valid,IBAN n'est pas valide,
|
IBAN is not valid,IBAN n'est pas valide,
|
||||||
Import Data from CSV / Excel files.,Importer des données à partir de fichiers CSV / Excel,
|
Import Data from CSV / Excel files.,Importer des données à partir de fichiers CSV / Excel,
|
||||||
@@ -3880,7 +3879,7 @@ Only expired allocation can be cancelled,Seule l'allocation expirée peut être
|
|||||||
Only users with the {0} role can create backdated leave applications,Seuls les utilisateurs avec le rôle {0} peuvent créer des demandes de congé antidatées,
|
Only users with the {0} role can create backdated leave applications,Seuls les utilisateurs avec le rôle {0} peuvent créer des demandes de congé antidatées,
|
||||||
Open,Ouvert,
|
Open,Ouvert,
|
||||||
Open Contact,Contact ouvert,
|
Open Contact,Contact ouvert,
|
||||||
Open Lead,Ouvrir le Prospect,
|
Open Lead,Ouvrir le Lead,
|
||||||
Opening and Closing,Ouverture et fermeture,
|
Opening and Closing,Ouverture et fermeture,
|
||||||
Operating Cost as per Work Order / BOM,Coût d'exploitation selon l'ordre de fabrication / nomenclature,
|
Operating Cost as per Work Order / BOM,Coût d'exploitation selon l'ordre de fabrication / nomenclature,
|
||||||
Order Amount,Montant de la commande,
|
Order Amount,Montant de la commande,
|
||||||
@@ -3926,7 +3925,7 @@ Please select another payment method. Stripe does not support transactions in cu
|
|||||||
Please select the customer.,S'il vous plaît sélectionner le client.,
|
Please select the customer.,S'il vous plaît sélectionner le client.,
|
||||||
Please set a Supplier against the Items to be considered in the Purchase Order.,Veuillez définir un fournisseur par rapport aux articles à prendre en compte dans la Commande d'Achat.,
|
Please set a Supplier against the Items to be considered in the Purchase Order.,Veuillez définir un fournisseur par rapport aux articles à prendre en compte dans la Commande d'Achat.,
|
||||||
Please set account heads in GST Settings for Compnay {0},Définissez les en-têtes de compte dans les paramètres de la TPS pour le service {0}.,
|
Please set account heads in GST Settings for Compnay {0},Définissez les en-têtes de compte dans les paramètres de la TPS pour le service {0}.,
|
||||||
Please set an email id for the Lead {0},Veuillez définir un identifiant de messagerie pour le prospect {0}.,
|
Please set an email id for the Lead {0},Veuillez définir un identifiant de messagerie pour le lead {0}.,
|
||||||
Please set default UOM in Stock Settings,Veuillez définir l'UdM par défaut dans les paramètres de stock,
|
Please set default UOM in Stock Settings,Veuillez définir l'UdM par défaut dans les paramètres de stock,
|
||||||
Please set filter based on Item or Warehouse due to a large amount of entries.,Veuillez définir le filtre en fonction de l'article ou de l'entrepôt en raison d'une grande quantité d'entrées.,
|
Please set filter based on Item or Warehouse due to a large amount of entries.,Veuillez définir le filtre en fonction de l'article ou de l'entrepôt en raison d'une grande quantité d'entrées.,
|
||||||
Please set up the Campaign Schedule in the Campaign {0},Configurez le calendrier de la campagne dans la campagne {0}.,
|
Please set up the Campaign Schedule in the Campaign {0},Configurez le calendrier de la campagne dans la campagne {0}.,
|
||||||
@@ -4943,8 +4942,8 @@ Min Qty,Qté Min,
|
|||||||
Max Qty,Qté Max,
|
Max Qty,Qté Max,
|
||||||
Min Amt,Montant Min,
|
Min Amt,Montant Min,
|
||||||
Max Amt,Montant Max,
|
Max Amt,Montant Max,
|
||||||
"If rate is zero them item will be treated as ""Free Item""",Si le prix est à 0 alors l'article sera traité comme article gratuit
|
"If rate is zero them item will be treated as ""Free Item""",Si le prix est à 0 alors l'article sera traité comme article gratuit,
|
||||||
Is Recursive,Est récursif
|
Is Recursive,Est récursif,
|
||||||
"Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on","La remise sera appliquée séquentiellement telque : acheter 1 => recupérer 1, acheter 2 => recupérer 2, acheter 3 => recupérer 3, etc..."
|
"Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on","La remise sera appliquée séquentiellement telque : acheter 1 => recupérer 1, acheter 2 => recupérer 2, acheter 3 => recupérer 3, etc..."
|
||||||
Period Settings,Paramètres de période,
|
Period Settings,Paramètres de période,
|
||||||
Margin,Marge,
|
Margin,Marge,
|
||||||
@@ -5600,7 +5599,7 @@ Call Log,Journal d'appel,
|
|||||||
Received By,Reçu par,
|
Received By,Reçu par,
|
||||||
Caller Information,Informations sur l'appelant,
|
Caller Information,Informations sur l'appelant,
|
||||||
Contact Name,Nom du Contact,
|
Contact Name,Nom du Contact,
|
||||||
Lead Name,Nom du Prospect,
|
Lead Name,Nom du Lead,
|
||||||
Ringing,Sonnerie,
|
Ringing,Sonnerie,
|
||||||
Missed,Manqué,
|
Missed,Manqué,
|
||||||
Call Duration in seconds,Durée d'appel en secondes,
|
Call Duration in seconds,Durée d'appel en secondes,
|
||||||
@@ -5668,7 +5667,7 @@ Fulfilment Terms and Conditions,Termes et conditions d'exécution,
|
|||||||
Contract Template Fulfilment Terms,Conditions d'exécution du modèle de contrat,
|
Contract Template Fulfilment Terms,Conditions d'exécution du modèle de contrat,
|
||||||
Email Campaign,Campagne Email,
|
Email Campaign,Campagne Email,
|
||||||
Email Campaign For ,Campagne d'email pour,
|
Email Campaign For ,Campagne d'email pour,
|
||||||
Lead is an Organization,Le prospect est une organisation,
|
Lead is an Organization,Le Lead est une organisation,
|
||||||
CRM-LEAD-.YYYY.-,CRM-LEAD-.YYYY.-,
|
CRM-LEAD-.YYYY.-,CRM-LEAD-.YYYY.-,
|
||||||
Person Name,Nom de la Personne,
|
Person Name,Nom de la Personne,
|
||||||
Lost Quotation,Devis Perdu,
|
Lost Quotation,Devis Perdu,
|
||||||
@@ -5683,7 +5682,7 @@ Next Contact Date,Date du Prochain Contact,
|
|||||||
Ends On,Se termine le,
|
Ends On,Se termine le,
|
||||||
Address & Contact,Adresse & Contact,
|
Address & Contact,Adresse & Contact,
|
||||||
Mobile No.,N° Mobile.,
|
Mobile No.,N° Mobile.,
|
||||||
Lead Type,Type de Prospect,
|
Lead Type,Type de Lead,
|
||||||
Channel Partner,Partenaire de Canal,
|
Channel Partner,Partenaire de Canal,
|
||||||
Consultant,Consultant,
|
Consultant,Consultant,
|
||||||
Market Segment,Part de Marché,
|
Market Segment,Part de Marché,
|
||||||
@@ -5706,7 +5705,7 @@ Opportunity Lost Reason,Raison perdue,
|
|||||||
Potential Sales Deal,Ventes Potentielles,
|
Potential Sales Deal,Ventes Potentielles,
|
||||||
CRM-OPP-.YYYY.-,CRM-OPP-YYYY.-,
|
CRM-OPP-.YYYY.-,CRM-OPP-YYYY.-,
|
||||||
Opportunity From,Opportunité De,
|
Opportunity From,Opportunité De,
|
||||||
Customer / Lead Name,Nom du Client / Prospect,
|
Customer / Lead Name,Nom du Client / Lead,
|
||||||
Opportunity Type,Type d'Opportunité,
|
Opportunity Type,Type d'Opportunité,
|
||||||
Converted By,Converti par,
|
Converted By,Converti par,
|
||||||
Sales Stage,Stade de vente,
|
Sales Stage,Stade de vente,
|
||||||
@@ -5716,7 +5715,7 @@ To Discuss,À Discuter,
|
|||||||
With Items,Avec Articles,
|
With Items,Avec Articles,
|
||||||
Probability (%),Probabilité (%),
|
Probability (%),Probabilité (%),
|
||||||
Contact Info,Information du Contact,
|
Contact Info,Information du Contact,
|
||||||
Customer / Lead Address,Adresse du Client / Prospect,
|
Customer / Lead Address,Adresse du Lead / Prospect,
|
||||||
Contact Mobile No,N° de Portable du Contact,
|
Contact Mobile No,N° de Portable du Contact,
|
||||||
Enter name of campaign if source of enquiry is campaign,Entrez le nom de la campagne si la source de l'enquête est une campagne,
|
Enter name of campaign if source of enquiry is campaign,Entrez le nom de la campagne si la source de l'enquête est une campagne,
|
||||||
Opportunity Date,Date d'Opportunité,
|
Opportunity Date,Date d'Opportunité,
|
||||||
@@ -7240,7 +7239,7 @@ Replace,Remplacer,
|
|||||||
Update latest price in all BOMs,Mettre à jour le prix le plus récent dans toutes les nomenclatures,
|
Update latest price in all BOMs,Mettre à jour le prix le plus récent dans toutes les nomenclatures,
|
||||||
BOM Website Item,Article de nomenclature du Site Internet,
|
BOM Website Item,Article de nomenclature du Site Internet,
|
||||||
BOM Website Operation,Opération de nomenclature du Site Internet,
|
BOM Website Operation,Opération de nomenclature du Site Internet,
|
||||||
Operation Time,Durée de l'Opération
|
Operation Time,Durée de l'Opération,
|
||||||
PO-JOB.#####,PO-JOB. #####,
|
PO-JOB.#####,PO-JOB. #####,
|
||||||
Timing Detail,Détail du timing,
|
Timing Detail,Détail du timing,
|
||||||
Time Logs,Time Logs,
|
Time Logs,Time Logs,
|
||||||
@@ -7645,7 +7644,7 @@ Campaign Schedules,Horaires de campagne,
|
|||||||
Buyer of Goods and Services.,Acheteur des Biens et Services.,
|
Buyer of Goods and Services.,Acheteur des Biens et Services.,
|
||||||
CUST-.YYYY.-,CUST-.YYYY.-,
|
CUST-.YYYY.-,CUST-.YYYY.-,
|
||||||
Default Company Bank Account,Compte bancaire d'entreprise par défaut,
|
Default Company Bank Account,Compte bancaire d'entreprise par défaut,
|
||||||
From Lead,Du Prospect,
|
From Lead,Du Lead,
|
||||||
Account Manager,Gestionnaire de compte,
|
Account Manager,Gestionnaire de compte,
|
||||||
Allow Sales Invoice Creation Without Sales Order,Autoriser la création de factures de vente sans commande client,
|
Allow Sales Invoice Creation Without Sales Order,Autoriser la création de factures de vente sans commande client,
|
||||||
Allow Sales Invoice Creation Without Delivery Note,Autoriser la création de factures de vente sans bon de livraison,
|
Allow Sales Invoice Creation Without Delivery Note,Autoriser la création de factures de vente sans bon de livraison,
|
||||||
@@ -7672,7 +7671,7 @@ Installation Date,Date d'Installation,
|
|||||||
Installation Time,Temps d'Installation,
|
Installation Time,Temps d'Installation,
|
||||||
Installation Note Item,Article Remarque d'Installation,
|
Installation Note Item,Article Remarque d'Installation,
|
||||||
Installed Qty,Qté Installée,
|
Installed Qty,Qté Installée,
|
||||||
Lead Source,Source du Prospect,
|
Lead Source,Source du Lead,
|
||||||
Period Start Date,Date de début de la période,
|
Period Start Date,Date de début de la période,
|
||||||
Period End Date,Date de fin de la période,
|
Period End Date,Date de fin de la période,
|
||||||
Cashier,Caissier,
|
Cashier,Caissier,
|
||||||
@@ -8517,8 +8516,8 @@ Item-wise Sales Register,Registre des Ventes par Article,
|
|||||||
Items To Be Requested,Articles À Demander,
|
Items To Be Requested,Articles À Demander,
|
||||||
Reserved,Réservé,
|
Reserved,Réservé,
|
||||||
Itemwise Recommended Reorder Level,Renouvellement Recommandé par Article,
|
Itemwise Recommended Reorder Level,Renouvellement Recommandé par Article,
|
||||||
Lead Details,Détails du Prospect,
|
Lead Details,Détails du Lead,
|
||||||
Lead Owner Efficiency,Efficacité des Responsables des Prospects,
|
Lead Owner Efficiency,Efficacité des Responsables des Leads,
|
||||||
Loan Repayment and Closure,Remboursement et clôture de prêts,
|
Loan Repayment and Closure,Remboursement et clôture de prêts,
|
||||||
Loan Security Status,État de la sécurité du prêt,
|
Loan Security Status,État de la sécurité du prêt,
|
||||||
Lost Opportunity,Occasion perdue,
|
Lost Opportunity,Occasion perdue,
|
||||||
@@ -9207,7 +9206,7 @@ Time Required (In Mins),Temps requis (en minutes),
|
|||||||
From Posting Date,À partir de la date de publication,
|
From Posting Date,À partir de la date de publication,
|
||||||
To Posting Date,À la date de publication,
|
To Posting Date,À la date de publication,
|
||||||
No records found,Aucun enregistrement trouvé,
|
No records found,Aucun enregistrement trouvé,
|
||||||
Customer/Lead Name,Nom du client / prospect,
|
Customer/Lead Name,Nom du client / lead,
|
||||||
Unmarked Days,Jours non marqués,
|
Unmarked Days,Jours non marqués,
|
||||||
Jan,Jan,
|
Jan,Jan,
|
||||||
Feb,fév,
|
Feb,fév,
|
||||||
@@ -9471,7 +9470,7 @@ Row {0}: Loan Security {1} added multiple times,Ligne {0}: Garantie de prêt {1}
|
|||||||
Row #{0}: Child Item should not be a Product Bundle. Please remove Item {1} and Save,Ligne n ° {0}: l'élément enfant ne doit pas être un ensemble de produits. Veuillez supprimer l'élément {1} et enregistrer,
|
Row #{0}: Child Item should not be a Product Bundle. Please remove Item {1} and Save,Ligne n ° {0}: l'élément enfant ne doit pas être un ensemble de produits. Veuillez supprimer l'élément {1} et enregistrer,
|
||||||
Credit limit reached for customer {0},Limite de crédit atteinte pour le client {0},
|
Credit limit reached for customer {0},Limite de crédit atteinte pour le client {0},
|
||||||
Could not auto create Customer due to the following missing mandatory field(s):,Impossible de créer automatiquement le client en raison du ou des champs obligatoires manquants suivants:,
|
Could not auto create Customer due to the following missing mandatory field(s):,Impossible de créer automatiquement le client en raison du ou des champs obligatoires manquants suivants:,
|
||||||
Please create Customer from Lead {0}.,Veuillez créer un client à partir du prospect {0}.,
|
Please create Customer from Lead {0}.,Veuillez créer un client à partir du lead {0}.,
|
||||||
Mandatory Missing,Obligatoire manquant,
|
Mandatory Missing,Obligatoire manquant,
|
||||||
Please set Payroll based on in Payroll settings,Veuillez définir la paie en fonction des paramètres de paie,
|
Please set Payroll based on in Payroll settings,Veuillez définir la paie en fonction des paramètres de paie,
|
||||||
Additional Salary: {0} already exist for Salary Component: {1} for period {2} and {3},Salaire supplémentaire: {0} existe déjà pour le composant de salaire: {1} pour la période {2} et {3},
|
Additional Salary: {0} already exist for Salary Component: {1} for period {2} and {3},Salaire supplémentaire: {0} existe déjà pour le composant de salaire: {1} pour la période {2} et {3},
|
||||||
@@ -9834,29 +9833,29 @@ Enable European Access,Activer l'accès européen,
|
|||||||
Creating Purchase Order ...,Création d'une commande d'achat ...,
|
Creating Purchase Order ...,Création d'une commande d'achat ...,
|
||||||
"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Sélectionnez un fournisseur parmi les fournisseurs par défaut des articles ci-dessous. Lors de la sélection, une commande d'achat sera effectué contre des articles appartenant uniquement au fournisseur sélectionné.",
|
"Select a Supplier from the Default Suppliers of the items below. On selection, a Purchase Order will be made against items belonging to the selected Supplier only.","Sélectionnez un fournisseur parmi les fournisseurs par défaut des articles ci-dessous. Lors de la sélection, une commande d'achat sera effectué contre des articles appartenant uniquement au fournisseur sélectionné.",
|
||||||
Row #{}: You must select {} serial numbers for item {}.,Ligne n ° {}: vous devez sélectionner {} numéros de série pour l'article {}.,
|
Row #{}: You must select {} serial numbers for item {}.,Ligne n ° {}: vous devez sélectionner {} numéros de série pour l'article {}.,
|
||||||
Update Rate as per Last Purchase,Mettre à jour avec les derniers prix d'achats
|
Update Rate as per Last Purchase,Mettre à jour avec les derniers prix d'achats,
|
||||||
Company Shipping Address,Adresse d'expédition
|
Company Shipping Address,Adresse d'expédition,
|
||||||
Shipping Address Details,Détail d'adresse d'expédition
|
Shipping Address Details,Détail d'adresse d'expédition,
|
||||||
Company Billing Address,Adresse de la société de facturation
|
Company Billing Address,Adresse de la société de facturation,
|
||||||
Supplier Address Details,
|
Supplier Address Details,
|
||||||
Bank Reconciliation Tool,Outil de réconcialiation d'écritures bancaires
|
Bank Reconciliation Tool,Outil de réconcialiation d'écritures bancaires,
|
||||||
Supplier Contact,Contact fournisseur
|
Supplier Contact,Contact fournisseur,
|
||||||
Subcontracting,Sous traitance
|
Subcontracting,Sous traitance,
|
||||||
Order Status,Statut de la commande
|
Order Status,Statut de la commande,
|
||||||
Build,Personnalisations avancées
|
Build,Personnalisations avancées,
|
||||||
Dispatch Address Name,Adresse de livraison intermédiaire
|
Dispatch Address Name,Adresse de livraison intermédiaire,
|
||||||
Amount Eligible for Commission,Montant éligible à comission
|
Amount Eligible for Commission,Montant éligible à comission,
|
||||||
Grant Commission,Eligible aux commissions
|
Grant Commission,Eligible aux commissions,
|
||||||
Stock Transactions Settings, Paramétre des transactions
|
Stock Transactions Settings, Paramétre des transactions,
|
||||||
Role Allowed to Over Deliver/Receive, Rôle autorisé à dépasser cette limite
|
Role Allowed to Over Deliver/Receive, Rôle autorisé à dépasser cette limite,
|
||||||
Users with this role are allowed to over deliver/receive against orders above the allowance percentage,Rôle Utilisateur qui sont autorisé à livrée/commandé au-delà de la limite
|
Users with this role are allowed to over deliver/receive against orders above the allowance percentage,Rôle Utilisateur qui sont autorisé à livrée/commandé au-delà de la limite,
|
||||||
Over Transfer Allowance,Autorisation de limite de transfert
|
Over Transfer Allowance,Autorisation de limite de transfert,
|
||||||
Quality Inspection Settings,Paramétre de l'inspection qualité
|
Quality Inspection Settings,Paramétre de l'inspection qualité,
|
||||||
Action If Quality Inspection Is Rejected,Action si l'inspection qualité est rejetée
|
Action If Quality Inspection Is Rejected,Action si l'inspection qualité est rejetée,
|
||||||
Disable Serial No And Batch Selector,Désactiver le sélecteur de numéro de lot/série
|
Disable Serial No And Batch Selector,Désactiver le sélecteur de numéro de lot/série,
|
||||||
Is Rate Adjustment Entry (Debit Note),Est un justement du prix de la note de débit
|
Is Rate Adjustment Entry (Debit Note),Est un justement du prix de la note de débit,
|
||||||
Issue a debit note with 0 qty against an existing Sales Invoice,Creer une note de débit avec une quatité à O pour la facture
|
Issue a debit note with 0 qty against an existing Sales Invoice,Creer une note de débit avec une quatité à O pour la facture,
|
||||||
Control Historical Stock Transactions,Controle de l'historique des stransaction de stock
|
Control Historical Stock Transactions,Controle de l'historique des stransaction de stock,
|
||||||
No stock transactions can be created or modified before this date.,Aucune transaction ne peux être créée ou modifié avant cette date.
|
No stock transactions can be created or modified before this date.,Aucune transaction ne peux être créée ou modifié avant cette date.
|
||||||
Stock transactions that are older than the mentioned days cannot be modified.,Les transactions de stock plus ancienne que le nombre de jours ci-dessus ne peuvent être modifiées,
|
Stock transactions that are older than the mentioned days cannot be modified.,Les transactions de stock plus ancienne que le nombre de jours ci-dessus ne peuvent être modifiées,
|
||||||
Role Allowed to Create/Edit Back-dated Transactions,Rôle autorisé à créer et modifier des transactions anti-datée,
|
Role Allowed to Create/Edit Back-dated Transactions,Rôle autorisé à créer et modifier des transactions anti-datée,
|
||||||
@@ -9867,29 +9866,29 @@ Show Barcode Field in Stock Transactions,Afficher le champ Code Barre dans les t
|
|||||||
Convert Item Description to Clean HTML in Transactions,Convertir les descriptions d'articles en HTML valide lors des transactions,
|
Convert Item Description to Clean HTML in Transactions,Convertir les descriptions d'articles en HTML valide lors des transactions,
|
||||||
Have Default Naming Series for Batch ID?,Masque de numérotation par défaut pour les Lots ou Séries,
|
Have Default Naming Series for Batch ID?,Masque de numérotation par défaut pour les Lots ou Séries,
|
||||||
"The percentage you are allowed to transfer more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed transfer 110 units","Le pourcentage de quantité que vous pourrez réceptionner en plus de la quantité commandée. Par exemple, vous avez commandé 100 unités, votre pourcentage de dépassement est de 10%, vous pourrez réceptionner 110 unités"
|
"The percentage you are allowed to transfer more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed transfer 110 units","Le pourcentage de quantité que vous pourrez réceptionner en plus de la quantité commandée. Par exemple, vous avez commandé 100 unités, votre pourcentage de dépassement est de 10%, vous pourrez réceptionner 110 unités"
|
||||||
Allowed Items,Articles autorisés
|
Allowed Items,Articles autorisés,
|
||||||
Party Specific Item,Restriction d'article disponible
|
Party Specific Item,Restriction d'article disponible,
|
||||||
Restrict Items Based On,Type de critére de restriction
|
Restrict Items Based On,Type de critére de restriction,
|
||||||
Based On Value,critére de restriction
|
Based On Value,critére de restriction,
|
||||||
Unit of Measure (UOM),Unité de mesure (UdM),
|
Unit of Measure (UOM),Unité de mesure (UdM),
|
||||||
Unit Of Measure (UOM),Unité de mesure (UdM),
|
Unit Of Measure (UOM),Unité de mesure (UdM),
|
||||||
CRM Settings,Paramètres CRM
|
CRM Settings,Paramètres CRM,
|
||||||
Do Not Explode,Ne pas décomposer
|
Do Not Explode,Ne pas décomposer,
|
||||||
Quick Access, Accés rapides
|
Quick Access, Accés rapides,
|
||||||
{} Available,{} Disponible.s
|
{} Available,{} Disponible.s,
|
||||||
{} Pending,{} En attente.s
|
{} Pending,{} En attente.s,
|
||||||
{} To Bill,{} à facturer
|
{} To Bill,{} à facturer,
|
||||||
{} To Receive,{} A recevoir
|
{} To Receive,{} A recevoir,
|
||||||
{} Active,{} Actif.ve(s)
|
{} Active,{} Actif.ve(s)
|
||||||
{} Open,{} Ouvert.e(s)
|
{} Open,{} Ouvert.e(s)
|
||||||
Incorrect Data Report,Rapport de données incohérentes
|
Incorrect Data Report,Rapport de données incohérentes,
|
||||||
Incorrect Serial No Valuation,Valorisation inccorecte par Num. Série / Lots
|
Incorrect Serial No Valuation,Valorisation inccorecte par Num. Série / Lots,
|
||||||
Incorrect Balance Qty After Transaction,Equilibre des quantités aprés une transaction
|
Incorrect Balance Qty After Transaction,Equilibre des quantités aprés une transaction,
|
||||||
Interview Type,Type d'entretien
|
Interview Type,Type d'entretien
|
||||||
Interview Round,Cycle d'entretien
|
Interview Round,Cycle d'entretien
|
||||||
Interview,Entretien
|
Interview,Entretien
|
||||||
Interview Feedback,Retour d'entretien
|
Interview Feedback,Retour d'entretien
|
||||||
Journal Energy Point,Historique des points d'énergies
|
Journal Energy Point,Historique des points d'énergies,
|
||||||
Billing Address Details,Adresse de facturation (détails)
|
Billing Address Details,Adresse de facturation (détails)
|
||||||
Supplier Address Details,Adresse Fournisseur (détails)
|
Supplier Address Details,Adresse Fournisseur (détails)
|
||||||
Retail,Commerce,
|
Retail,Commerce,
|
||||||
|
|||||||
|
Can't render this file because it is too large.
|
@@ -2364,7 +2364,7 @@ Report Type is mandatory,Rapport type is verplicht,
|
|||||||
Reports,rapporten,
|
Reports,rapporten,
|
||||||
Reqd By Date,Benodigd op datum,
|
Reqd By Date,Benodigd op datum,
|
||||||
Reqd Qty,Gewenste hoeveelheid,
|
Reqd Qty,Gewenste hoeveelheid,
|
||||||
Request for Quotation,Offerte,
|
Request for Quotation,Offerte-verzoek,
|
||||||
Request for Quotations,Verzoek om offertes,
|
Request for Quotations,Verzoek om offertes,
|
||||||
Request for Raw Materials,Verzoek om grondstoffen,
|
Request for Raw Materials,Verzoek om grondstoffen,
|
||||||
Request for purchase.,Inkoopaanvraag,
|
Request for purchase.,Inkoopaanvraag,
|
||||||
|
|||||||
|
Can't render this file because it is too large.
|
Reference in New Issue
Block a user