Merge branch 'develop' into fix/subcontracting-receipt/gl-entries
This commit is contained in:
commit
f19049e643
32
.github/workflows/initiate_release.yml
vendored
Normal file
32
.github/workflows/initiate_release.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# This workflow is agnostic to branches. Only maintain on develop branch.
|
||||||
|
# To add/remove versions just modify the matrix.
|
||||||
|
|
||||||
|
name: Create weekly release pull requests
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# 9:30 UTC => 3 PM IST Tuesday
|
||||||
|
- cron: "30 9 * * 2"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
version: ["13", "14"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: octokit/request-action@v2.x
|
||||||
|
with:
|
||||||
|
route: POST /repos/{owner}/{repo}/pulls
|
||||||
|
owner: frappe
|
||||||
|
repo: erpnext
|
||||||
|
title: |-
|
||||||
|
"chore: release v${{ matrix.version }}"
|
||||||
|
body: "Automated weekly release."
|
||||||
|
base: version-${{ matrix.version }}
|
||||||
|
head: version-${{ matrix.version }}-hotfix
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
@ -14,8 +14,8 @@ pos* @nextchamp-saqib
|
|||||||
erpnext/buying/ @rohitwaghchaure @s-aga-r
|
erpnext/buying/ @rohitwaghchaure @s-aga-r
|
||||||
erpnext/maintenance/ @rohitwaghchaure @s-aga-r
|
erpnext/maintenance/ @rohitwaghchaure @s-aga-r
|
||||||
erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
|
erpnext/manufacturing/ @rohitwaghchaure @s-aga-r
|
||||||
erpnext/quality_management/ @marination @rohitwaghchaure @s-aga-r
|
erpnext/quality_management/ @rohitwaghchaure @s-aga-r
|
||||||
erpnext/stock/ @marination @rohitwaghchaure @s-aga-r
|
erpnext/stock/ @rohitwaghchaure @s-aga-r
|
||||||
|
|
||||||
erpnext/crm/ @NagariaHussain
|
erpnext/crm/ @NagariaHussain
|
||||||
erpnext/education/ @rutwikhdev
|
erpnext/education/ @rutwikhdev
|
||||||
|
@ -366,7 +366,7 @@ def update_outstanding_amt(
|
|||||||
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
|
if against_voucher_type in ["Sales Invoice", "Purchase Invoice", "Fees"]:
|
||||||
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
|
ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
|
||||||
|
|
||||||
# Didn't use db_set for optimisation purpose
|
# Didn't use db_set for optimization purpose
|
||||||
ref_doc.outstanding_amount = bal
|
ref_doc.outstanding_amount = bal
|
||||||
frappe.db.set_value(against_voucher_type, against_voucher, "outstanding_amount", bal)
|
frappe.db.set_value(against_voucher_type, against_voucher, "outstanding_amount", bal)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on("Journal Entry Template", {
|
frappe.ui.form.on("Journal Entry Template", {
|
||||||
setup: function(frm) {
|
refresh: function(frm) {
|
||||||
frappe.model.set_default_values(frm.doc);
|
frappe.model.set_default_values(frm.doc);
|
||||||
|
|
||||||
frm.set_query("account" ,"accounts", function(){
|
frm.set_query("account" ,"accounts", function(){
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
"amount",
|
"amount",
|
||||||
"account_currency",
|
"account_currency",
|
||||||
"amount_in_account_currency",
|
"amount_in_account_currency",
|
||||||
"delinked"
|
"delinked",
|
||||||
|
"remarks"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -136,12 +137,17 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Finance Book",
|
"label": "Finance Book",
|
||||||
"options": "Finance Book"
|
"options": "Finance Book"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "remarks",
|
||||||
|
"fieldtype": "Text",
|
||||||
|
"label": "Remarks"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-07-11 09:13:54.379168",
|
"modified": "2022-08-22 15:32:56.629430",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Ledger Entry",
|
"name": "Payment Ledger Entry",
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
"currency",
|
"currency",
|
||||||
"write_off_account",
|
"write_off_account",
|
||||||
"write_off_cost_center",
|
"write_off_cost_center",
|
||||||
|
"write_off_limit",
|
||||||
"account_for_change_amount",
|
"account_for_change_amount",
|
||||||
"disable_rounded_total",
|
"disable_rounded_total",
|
||||||
"column_break_23",
|
"column_break_23",
|
||||||
@ -360,6 +361,14 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Validate Stock on Save"
|
"label": "Validate Stock on Save"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"default": "1",
|
||||||
|
"description": "Auto write off precision loss while consolidation",
|
||||||
|
"fieldname": "write_off_limit",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Write Off Limit",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "If enabled, the consolidated invoices will have rounded total disabled",
|
"description": "If enabled, the consolidated invoices will have rounded total disabled",
|
||||||
@ -393,7 +402,7 @@
|
|||||||
"link_fieldname": "pos_profile"
|
"link_fieldname": "pos_profile"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"modified": "2022-07-21 11:16:46.911173",
|
"modified": "2022-08-10 12:57:06.241439",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "POS Profile",
|
"name": "POS Profile",
|
||||||
|
@ -34,4 +34,4 @@ class ProcessDeferredAccounting(Document):
|
|||||||
filters={"against_voucher_type": self.doctype, "against_voucher": self.name},
|
filters={"against_voucher_type": self.doctype, "against_voucher": self.name},
|
||||||
)
|
)
|
||||||
|
|
||||||
make_gl_entries(gl_entries=gl_entries, cancel=1)
|
make_gl_entries(gl_map=gl_entries, cancel=1)
|
||||||
|
@ -57,3 +57,16 @@ class TestProcessDeferredAccounting(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
|
|
||||||
check_gl_entries(self, si.name, expected_gle, "2019-01-10")
|
check_gl_entries(self, si.name, expected_gle, "2019-01-10")
|
||||||
|
|
||||||
|
def test_pda_submission_and_cancellation(self):
|
||||||
|
pda = frappe.get_doc(
|
||||||
|
dict(
|
||||||
|
doctype="Process Deferred Accounting",
|
||||||
|
posting_date="2019-01-01",
|
||||||
|
start_date="2019-01-01",
|
||||||
|
end_date="2019-01-31",
|
||||||
|
type="Income",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pda.submit()
|
||||||
|
pda.cancel()
|
||||||
|
@ -575,7 +575,6 @@ class PurchaseInvoice(BuyingController):
|
|||||||
|
|
||||||
self.make_supplier_gl_entry(gl_entries)
|
self.make_supplier_gl_entry(gl_entries)
|
||||||
self.make_item_gl_entries(gl_entries)
|
self.make_item_gl_entries(gl_entries)
|
||||||
self.make_discount_gl_entries(gl_entries)
|
|
||||||
|
|
||||||
if self.check_asset_cwip_enabled():
|
if self.check_asset_cwip_enabled():
|
||||||
self.get_asset_gl_entry(gl_entries)
|
self.get_asset_gl_entry(gl_entries)
|
||||||
@ -807,7 +806,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not item.is_fixed_asset:
|
if not item.is_fixed_asset:
|
||||||
dummy, amount = self.get_amount_and_base_amount(item, enable_discount_accounting)
|
dummy, amount = self.get_amount_and_base_amount(item, None)
|
||||||
else:
|
else:
|
||||||
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
|
amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
|
||||||
|
|
||||||
@ -1165,7 +1164,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for tax in self.get("taxes"):
|
for tax in self.get("taxes"):
|
||||||
amount, base_amount = self.get_tax_amounts(tax, enable_discount_accounting)
|
amount, base_amount = self.get_tax_amounts(tax, None)
|
||||||
if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
|
if tax.category in ("Total", "Valuation and Total") and flt(base_amount):
|
||||||
account_currency = get_account_currency(tax.account_head)
|
account_currency = get_account_currency(tax.account_head)
|
||||||
|
|
||||||
|
@ -338,59 +338,6 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin):
|
|||||||
|
|
||||||
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
|
self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount)
|
||||||
|
|
||||||
@change_settings("Buying Settings", {"enable_discount_accounting": 1})
|
|
||||||
def test_purchase_invoice_with_discount_accounting_enabled(self):
|
|
||||||
|
|
||||||
discount_account = create_account(
|
|
||||||
account_name="Discount Account",
|
|
||||||
parent_account="Indirect Expenses - _TC",
|
|
||||||
company="_Test Company",
|
|
||||||
)
|
|
||||||
pi = make_purchase_invoice(discount_account=discount_account, rate=45)
|
|
||||||
|
|
||||||
expected_gle = [
|
|
||||||
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
|
|
||||||
["Creditors - _TC", 0.0, 225.0, nowdate()],
|
|
||||||
["Discount Account - _TC", 0.0, 25.0, nowdate()],
|
|
||||||
]
|
|
||||||
|
|
||||||
check_gl_entries(self, pi.name, expected_gle, nowdate())
|
|
||||||
|
|
||||||
@change_settings("Buying Settings", {"enable_discount_accounting": 1})
|
|
||||||
def test_additional_discount_for_purchase_invoice_with_discount_accounting_enabled(self):
|
|
||||||
|
|
||||||
additional_discount_account = create_account(
|
|
||||||
account_name="Discount Account",
|
|
||||||
parent_account="Indirect Expenses - _TC",
|
|
||||||
company="_Test Company",
|
|
||||||
)
|
|
||||||
|
|
||||||
pi = make_purchase_invoice(do_not_save=1, parent_cost_center="Main - _TC")
|
|
||||||
pi.apply_discount_on = "Grand Total"
|
|
||||||
pi.additional_discount_account = additional_discount_account
|
|
||||||
pi.additional_discount_percentage = 10
|
|
||||||
pi.disable_rounded_total = 1
|
|
||||||
pi.append(
|
|
||||||
"taxes",
|
|
||||||
{
|
|
||||||
"charge_type": "On Net Total",
|
|
||||||
"account_head": "_Test Account VAT - _TC",
|
|
||||||
"cost_center": "Main - _TC",
|
|
||||||
"description": "Test",
|
|
||||||
"rate": 10,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
pi.submit()
|
|
||||||
|
|
||||||
expected_gle = [
|
|
||||||
["_Test Account Cost for Goods Sold - _TC", 250.0, 0.0, nowdate()],
|
|
||||||
["_Test Account VAT - _TC", 25.0, 0.0, nowdate()],
|
|
||||||
["Creditors - _TC", 0.0, 247.5, nowdate()],
|
|
||||||
["Discount Account - _TC", 0.0, 27.5, nowdate()],
|
|
||||||
]
|
|
||||||
|
|
||||||
check_gl_entries(self, pi.name, expected_gle, nowdate())
|
|
||||||
|
|
||||||
def test_purchase_invoice_change_naming_series(self):
|
def test_purchase_invoice_change_naming_series(self):
|
||||||
pi = frappe.copy_doc(test_records[1])
|
pi = frappe.copy_doc(test_records[1])
|
||||||
pi.insert()
|
pi.insert()
|
||||||
|
@ -479,9 +479,13 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e
|
|||||||
|
|
||||||
is_cash_or_non_trade_discount() {
|
is_cash_or_non_trade_discount() {
|
||||||
this.frm.set_df_property("additional_discount_account", "hidden", 1 - this.frm.doc.is_cash_or_non_trade_discount);
|
this.frm.set_df_property("additional_discount_account", "hidden", 1 - this.frm.doc.is_cash_or_non_trade_discount);
|
||||||
|
this.frm.set_df_property("additional_discount_account", "reqd", this.frm.doc.is_cash_or_non_trade_discount);
|
||||||
|
|
||||||
if (!this.frm.doc.is_cash_or_non_trade_discount) {
|
if (!this.frm.doc.is_cash_or_non_trade_discount) {
|
||||||
this.frm.set_value("additional_discount_account", "");
|
this.frm.set_value("additional_discount_account", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.calculate_taxes_and_totals();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -710,6 +710,7 @@ class SalesInvoice(SellingController):
|
|||||||
if (
|
if (
|
||||||
cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate"))
|
cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate"))
|
||||||
and not self.is_return
|
and not self.is_return
|
||||||
|
and not self.is_internal_customer
|
||||||
):
|
):
|
||||||
self.validate_rate_with_reference_doc(
|
self.validate_rate_with_reference_doc(
|
||||||
[["Sales Order", "sales_order", "so_detail"], ["Delivery Note", "delivery_note", "dn_detail"]]
|
[["Sales Order", "sales_order", "so_detail"], ["Delivery Note", "delivery_note", "dn_detail"]]
|
||||||
@ -1033,22 +1034,6 @@ class SalesInvoice(SellingController):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.apply_discount_on == "Grand Total" and self.get("is_cash_or_discount_account"):
|
|
||||||
gl_entries.append(
|
|
||||||
self.get_gl_dict(
|
|
||||||
{
|
|
||||||
"account": self.additional_discount_account,
|
|
||||||
"against": self.debit_to,
|
|
||||||
"debit": self.base_discount_amount,
|
|
||||||
"debit_in_account_currency": self.discount_amount,
|
|
||||||
"cost_center": self.cost_center,
|
|
||||||
"project": self.project,
|
|
||||||
},
|
|
||||||
self.currency,
|
|
||||||
item=self,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def make_tax_gl_entries(self, gl_entries):
|
def make_tax_gl_entries(self, gl_entries):
|
||||||
enable_discount_accounting = cint(
|
enable_discount_accounting = cint(
|
||||||
frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
|
frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
|
||||||
@ -2177,6 +2162,17 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
|||||||
|
|
||||||
def update_item(source, target, source_parent):
|
def update_item(source, target, source_parent):
|
||||||
target.qty = flt(source.qty) - received_items.get(source.name, 0.0)
|
target.qty = flt(source.qty) - received_items.get(source.name, 0.0)
|
||||||
|
if source.doctype == "Purchase Order Item" and target.doctype == "Sales Order Item":
|
||||||
|
target.purchase_order = source.parent
|
||||||
|
target.purchase_order_item = source.name
|
||||||
|
|
||||||
|
if (
|
||||||
|
source.get("purchase_order")
|
||||||
|
and source.get("purchase_order_item")
|
||||||
|
and target.doctype == "Purchase Invoice Item"
|
||||||
|
):
|
||||||
|
target.purchase_order = source.purchase_order
|
||||||
|
target.po_detail = source.purchase_order_item
|
||||||
|
|
||||||
item_field_map = {
|
item_field_map = {
|
||||||
"doctype": target_doctype + " Item",
|
"doctype": target_doctype + " Item",
|
||||||
@ -2203,6 +2199,12 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
|||||||
"serial_no": "serial_no",
|
"serial_no": "serial_no",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
elif target_doctype == "Sales Order":
|
||||||
|
item_field_map["field_map"].update(
|
||||||
|
{
|
||||||
|
source_document_warehouse_field: "warehouse",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
doclist = get_mapped_doc(
|
doclist = get_mapped_doc(
|
||||||
doctype,
|
doctype,
|
||||||
@ -2247,6 +2249,7 @@ def get_received_items(reference_name, doctype, reference_fieldname):
|
|||||||
|
|
||||||
def set_purchase_references(doc):
|
def set_purchase_references(doc):
|
||||||
# add internal PO or PR links if any
|
# add internal PO or PR links if any
|
||||||
|
|
||||||
if doc.is_internal_transfer():
|
if doc.is_internal_transfer():
|
||||||
if doc.doctype == "Purchase Receipt":
|
if doc.doctype == "Purchase Receipt":
|
||||||
so_item_map = get_delivery_note_details(doc.inter_company_invoice_reference)
|
so_item_map = get_delivery_note_details(doc.inter_company_invoice_reference)
|
||||||
@ -2276,15 +2279,6 @@ def set_purchase_references(doc):
|
|||||||
warehouse_map,
|
warehouse_map,
|
||||||
)
|
)
|
||||||
|
|
||||||
if list(so_item_map.values()):
|
|
||||||
pd_item_map, parent_child_map, warehouse_map = get_pd_details(
|
|
||||||
"Purchase Order Item", so_item_map, "sales_order_item"
|
|
||||||
)
|
|
||||||
|
|
||||||
update_pi_items(
|
|
||||||
doc, "po_detail", "purchase_order", so_item_map, pd_item_map, parent_child_map, warehouse_map
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def update_pi_items(
|
def update_pi_items(
|
||||||
doc,
|
doc,
|
||||||
@ -2300,13 +2294,19 @@ def update_pi_items(
|
|||||||
item.set(parent_field, parent_child_map.get(sales_item_map.get(item.sales_invoice_item)))
|
item.set(parent_field, parent_child_map.get(sales_item_map.get(item.sales_invoice_item)))
|
||||||
if doc.update_stock:
|
if doc.update_stock:
|
||||||
item.warehouse = warehouse_map.get(sales_item_map.get(item.sales_invoice_item))
|
item.warehouse = warehouse_map.get(sales_item_map.get(item.sales_invoice_item))
|
||||||
|
if not item.warehouse and item.get("purchase_order") and item.get("purchase_order_item"):
|
||||||
|
item.warehouse = frappe.db.get_value(
|
||||||
|
"Purchase Order Item", item.purchase_order_item, "warehouse"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, warehouse_map):
|
def update_pr_items(doc, sales_item_map, purchase_item_map, parent_child_map, warehouse_map):
|
||||||
for item in doc.get("items"):
|
for item in doc.get("items"):
|
||||||
item.purchase_order_item = purchase_item_map.get(sales_item_map.get(item.delivery_note_item))
|
|
||||||
item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item))
|
item.warehouse = warehouse_map.get(sales_item_map.get(item.delivery_note_item))
|
||||||
item.purchase_order = parent_child_map.get(sales_item_map.get(item.delivery_note_item))
|
if not item.warehouse and item.get("purchase_order") and item.get("purchase_order_item"):
|
||||||
|
item.warehouse = frappe.db.get_value(
|
||||||
|
"Purchase Order Item", item.purchase_order_item, "warehouse"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_delivery_note_details(internal_reference):
|
def get_delivery_note_details(internal_reference):
|
||||||
|
@ -96,6 +96,10 @@
|
|||||||
"delivery_note",
|
"delivery_note",
|
||||||
"dn_detail",
|
"dn_detail",
|
||||||
"delivered_qty",
|
"delivered_qty",
|
||||||
|
"internal_transfer_section",
|
||||||
|
"purchase_order",
|
||||||
|
"column_break_92",
|
||||||
|
"purchase_order_item",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
@ -282,7 +286,6 @@
|
|||||||
"label": "Discount (%) on Price List Rate with Margin",
|
"label": "Discount (%) on Price List Rate with Margin",
|
||||||
"oldfieldname": "adj_rate",
|
"oldfieldname": "adj_rate",
|
||||||
"oldfieldtype": "Float",
|
"oldfieldtype": "Float",
|
||||||
"precision": "2",
|
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -841,12 +844,38 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Grant Commission",
|
"label": "Grant Commission",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"depends_on": "eval:parent.is_internal_customer == 1",
|
||||||
|
"fieldname": "internal_transfer_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Internal Transfer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Order",
|
||||||
|
"options": "Purchase Order",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_92",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order_item",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Purchase Order Item",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-17 05:33:15.335912",
|
"modified": "2022-09-06 14:17:43.394309",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Sales Invoice Item",
|
"name": "Sales Invoice Item",
|
||||||
|
@ -318,7 +318,6 @@ def get_advance_vouchers(
|
|||||||
"is_cancelled": 0,
|
"is_cancelled": 0,
|
||||||
"party_type": party_type,
|
"party_type": party_type,
|
||||||
"party": ["in", parties],
|
"party": ["in", parties],
|
||||||
"against_voucher": ["is", "not set"],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if company:
|
if company:
|
||||||
|
@ -178,6 +178,11 @@ frappe.query_reports["Accounts Receivable"] = {
|
|||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1
|
"hidden": 1
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "show_remarks",
|
||||||
|
"label": __("Show Remarks"),
|
||||||
|
"fieldtype": "Check",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "customer_name",
|
"fieldname": "customer_name",
|
||||||
"label": __("Customer Name"),
|
"label": __("Customer Name"),
|
||||||
|
@ -119,6 +119,7 @@ class ReceivablePayableReport(object):
|
|||||||
party_account=ple.account,
|
party_account=ple.account,
|
||||||
posting_date=ple.posting_date,
|
posting_date=ple.posting_date,
|
||||||
account_currency=ple.account_currency,
|
account_currency=ple.account_currency,
|
||||||
|
remarks=ple.remarks,
|
||||||
invoiced=0.0,
|
invoiced=0.0,
|
||||||
paid=0.0,
|
paid=0.0,
|
||||||
credit_note=0.0,
|
credit_note=0.0,
|
||||||
@ -178,6 +179,11 @@ class ReceivablePayableReport(object):
|
|||||||
|
|
||||||
key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
|
key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)
|
||||||
row = self.voucher_balance.get(key)
|
row = self.voucher_balance.get(key)
|
||||||
|
|
||||||
|
if not row:
|
||||||
|
# no invoice, this is an invoice / stand-alone payment / credit note
|
||||||
|
row = self.voucher_balance.get((ple.voucher_type, ple.voucher_no, ple.party))
|
||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
def update_voucher_balance(self, ple):
|
def update_voucher_balance(self, ple):
|
||||||
@ -187,7 +193,11 @@ class ReceivablePayableReport(object):
|
|||||||
if not row:
|
if not row:
|
||||||
return
|
return
|
||||||
|
|
||||||
amount = ple.amount
|
# amount in "Party Currency", if its supplied. If not, amount in company currency
|
||||||
|
if self.filters.get(scrub(self.party_type)):
|
||||||
|
amount = ple.amount_in_account_currency
|
||||||
|
else:
|
||||||
|
amount = ple.amount
|
||||||
amount_in_account_currency = ple.amount_in_account_currency
|
amount_in_account_currency = ple.amount_in_account_currency
|
||||||
|
|
||||||
# update voucher
|
# update voucher
|
||||||
@ -685,9 +695,10 @@ class ReceivablePayableReport(object):
|
|||||||
ple.party,
|
ple.party,
|
||||||
ple.posting_date,
|
ple.posting_date,
|
||||||
ple.due_date,
|
ple.due_date,
|
||||||
ple.account_currency.as_("currency"),
|
ple.account_currency,
|
||||||
ple.amount,
|
ple.amount,
|
||||||
ple.amount_in_account_currency,
|
ple.amount_in_account_currency,
|
||||||
|
ple.remarks,
|
||||||
)
|
)
|
||||||
.where(ple.delinked == 0)
|
.where(ple.delinked == 0)
|
||||||
.where(Criterion.all(self.qb_selection_filter))
|
.where(Criterion.all(self.qb_selection_filter))
|
||||||
@ -722,6 +733,7 @@ class ReceivablePayableReport(object):
|
|||||||
def prepare_conditions(self):
|
def prepare_conditions(self):
|
||||||
self.qb_selection_filter = []
|
self.qb_selection_filter = []
|
||||||
party_type_field = scrub(self.party_type)
|
party_type_field = scrub(self.party_type)
|
||||||
|
self.qb_selection_filter.append(self.ple.party_type == self.party_type)
|
||||||
|
|
||||||
self.add_common_filters(party_type_field=party_type_field)
|
self.add_common_filters(party_type_field=party_type_field)
|
||||||
|
|
||||||
@ -965,6 +977,9 @@ class ReceivablePayableReport(object):
|
|||||||
options="Supplier Group",
|
options="Supplier Group",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.filters.show_remarks:
|
||||||
|
self.add_column(label=_("Remarks"), fieldname="remarks", fieldtype="Text", width=200),
|
||||||
|
|
||||||
def add_column(self, label, fieldname=None, fieldtype="Currency", options=None, width=120):
|
def add_column(self, label, fieldname=None, fieldtype="Currency", options=None, width=120):
|
||||||
if not fieldname:
|
if not fieldname:
|
||||||
fieldname = scrub(label)
|
fieldname = scrub(label)
|
||||||
|
@ -1,19 +1,27 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import add_days, getdate, today
|
from frappe.utils import add_days, getdate, today
|
||||||
|
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
|
||||||
from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute
|
from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute
|
||||||
|
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||||
|
|
||||||
|
|
||||||
class TestAccountsReceivable(unittest.TestCase):
|
class TestAccountsReceivable(FrappeTestCase):
|
||||||
def test_accounts_receivable(self):
|
def setUp(self):
|
||||||
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'")
|
frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'")
|
||||||
|
frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'")
|
||||||
|
frappe.db.sql("delete from `tabPayment Entry` where company='_Test Company 2'")
|
||||||
frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'")
|
frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'")
|
||||||
frappe.db.sql("delete from `tabPayment Ledger Entry` where company='_Test Company 2'")
|
frappe.db.sql("delete from `tabPayment Ledger Entry` where company='_Test Company 2'")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
frappe.db.rollback()
|
||||||
|
|
||||||
|
def test_accounts_receivable(self):
|
||||||
filters = {
|
filters = {
|
||||||
"company": "_Test Company 2",
|
"company": "_Test Company 2",
|
||||||
"based_on_payment_terms": 1,
|
"based_on_payment_terms": 1,
|
||||||
@ -66,6 +74,50 @@ class TestAccountsReceivable(unittest.TestCase):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_payment_againt_po_in_receivable_report(self):
|
||||||
|
"""
|
||||||
|
Payments made against Purchase Order will show up as outstanding amount
|
||||||
|
"""
|
||||||
|
|
||||||
|
so = make_sales_order(
|
||||||
|
company="_Test Company 2",
|
||||||
|
customer="_Test Customer 2",
|
||||||
|
warehouse="Finished Goods - _TC2",
|
||||||
|
currency="EUR",
|
||||||
|
debit_to="Debtors - _TC2",
|
||||||
|
income_account="Sales - _TC2",
|
||||||
|
expense_account="Cost of Goods Sold - _TC2",
|
||||||
|
cost_center="Main - _TC2",
|
||||||
|
)
|
||||||
|
|
||||||
|
pe = get_payment_entry(so.doctype, so.name)
|
||||||
|
pe = pe.save().submit()
|
||||||
|
|
||||||
|
filters = {
|
||||||
|
"company": "_Test Company 2",
|
||||||
|
"based_on_payment_terms": 0,
|
||||||
|
"report_date": today(),
|
||||||
|
"range1": 30,
|
||||||
|
"range2": 60,
|
||||||
|
"range3": 90,
|
||||||
|
"range4": 120,
|
||||||
|
}
|
||||||
|
|
||||||
|
report = execute(filters)
|
||||||
|
|
||||||
|
expected_data_after_payment = [0, 1000, 0, -1000]
|
||||||
|
|
||||||
|
row = report[1][0]
|
||||||
|
self.assertEqual(
|
||||||
|
expected_data_after_payment,
|
||||||
|
[
|
||||||
|
row.invoiced,
|
||||||
|
row.paid,
|
||||||
|
row.credit_note,
|
||||||
|
row.outstanding,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_sales_invoice():
|
def make_sales_invoice():
|
||||||
frappe.set_user("Administrator")
|
frappe.set_user("Administrator")
|
||||||
|
@ -535,7 +535,11 @@ def get_accounts(root_type, companies):
|
|||||||
):
|
):
|
||||||
if account.account_name not in added_accounts:
|
if account.account_name not in added_accounts:
|
||||||
accounts.append(account)
|
accounts.append(account)
|
||||||
added_accounts.append(account.account_name)
|
if account.account_number:
|
||||||
|
account_key = account.account_number + "-" + account.account_name
|
||||||
|
else:
|
||||||
|
account_key = account.account_name
|
||||||
|
added_accounts.append(account_key)
|
||||||
|
|
||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
frappe.query_reports["Gross Profit"] = {
|
frappe.query_reports["Gross Profit"] = {
|
||||||
"filters": [
|
"filters": [
|
||||||
{
|
{
|
||||||
"fieldname":"company",
|
"fieldname": "company",
|
||||||
"label": __("Company"),
|
"label": __("Company"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
@ -12,32 +12,44 @@ frappe.query_reports["Gross Profit"] = {
|
|||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"from_date",
|
"fieldname": "from_date",
|
||||||
"label": __("From Date"),
|
"label": __("From Date"),
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"default": frappe.defaults.get_user_default("year_start_date"),
|
"default": frappe.defaults.get_user_default("year_start_date"),
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"to_date",
|
"fieldname": "to_date",
|
||||||
"label": __("To Date"),
|
"label": __("To Date"),
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"default": frappe.defaults.get_user_default("year_end_date"),
|
"default": frappe.defaults.get_user_default("year_end_date"),
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"sales_invoice",
|
"fieldname": "sales_invoice",
|
||||||
"label": __("Sales Invoice"),
|
"label": __("Sales Invoice"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"options": "Sales Invoice"
|
"options": "Sales Invoice"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"group_by",
|
"fieldname": "group_by",
|
||||||
"label": __("Group By"),
|
"label": __("Group By"),
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject\nMonthly\nPayment Term",
|
"options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject\nMonthly\nPayment Term",
|
||||||
"default": "Invoice"
|
"default": "Invoice"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "item_group",
|
||||||
|
"label": __("Item Group"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Item Group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sales_person",
|
||||||
|
"label": __("Sales Person"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Sales Person"
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"tree": true,
|
"tree": true,
|
||||||
"name_field": "parent",
|
"name_field": "parent",
|
||||||
|
@ -7,6 +7,7 @@ from frappe import _, scrub
|
|||||||
from frappe.utils import cint, flt, formatdate
|
from frappe.utils import cint, flt, formatdate
|
||||||
|
|
||||||
from erpnext.controllers.queries import get_match_cond
|
from erpnext.controllers.queries import get_match_cond
|
||||||
|
from erpnext.stock.report.stock_ledger.stock_ledger import get_item_group_condition
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
|
|
||||||
|
|
||||||
@ -676,6 +677,17 @@ class GrossProfitGenerator(object):
|
|||||||
if self.filters.to_date:
|
if self.filters.to_date:
|
||||||
conditions += " and posting_date <= %(to_date)s"
|
conditions += " and posting_date <= %(to_date)s"
|
||||||
|
|
||||||
|
if self.filters.item_group:
|
||||||
|
conditions += " and {0}".format(get_item_group_condition(self.filters.item_group))
|
||||||
|
|
||||||
|
if self.filters.sales_person:
|
||||||
|
conditions += """
|
||||||
|
and exists(select 1
|
||||||
|
from `tabSales Team` st
|
||||||
|
where st.parent = `tabSales Invoice`.name
|
||||||
|
and st.sales_person = %(sales_person)s)
|
||||||
|
"""
|
||||||
|
|
||||||
if self.filters.group_by == "Sales Person":
|
if self.filters.group_by == "Sales Person":
|
||||||
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
|
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
|
||||||
sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
|
sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
|
||||||
@ -723,6 +735,7 @@ class GrossProfitGenerator(object):
|
|||||||
from
|
from
|
||||||
`tabSales Invoice` inner join `tabSales Invoice Item`
|
`tabSales Invoice` inner join `tabSales Invoice Item`
|
||||||
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
|
||||||
|
join `tabItem` item on item.name = `tabSales Invoice Item`.item_code
|
||||||
{sales_team_table}
|
{sales_team_table}
|
||||||
{payment_term_table}
|
{payment_term_table}
|
||||||
where
|
where
|
||||||
|
@ -1424,6 +1424,7 @@ def create_payment_ledger_entry(
|
|||||||
"amount": dr_or_cr,
|
"amount": dr_or_cr,
|
||||||
"amount_in_account_currency": dr_or_cr_account_currency,
|
"amount_in_account_currency": dr_or_cr_account_currency,
|
||||||
"delinked": True if cancel else False,
|
"delinked": True if cancel else False,
|
||||||
|
"remarks": gle.remarks,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1454,12 +1454,14 @@ def create_fixed_asset_item(item_code=None, auto_create_assets=1, is_grouped_ass
|
|||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def set_depreciation_settings_in_company():
|
def set_depreciation_settings_in_company(company=None):
|
||||||
company = frappe.get_doc("Company", "_Test Company")
|
if not company:
|
||||||
company.accumulated_depreciation_account = "_Test Accumulated Depreciations - _TC"
|
company = "_Test Company"
|
||||||
company.depreciation_expense_account = "_Test Depreciations - _TC"
|
company = frappe.get_doc("Company", company)
|
||||||
company.disposal_account = "_Test Gain/Loss on Asset Disposal - _TC"
|
company.accumulated_depreciation_account = "_Test Accumulated Depreciations - " + company.abbr
|
||||||
company.depreciation_cost_center = "_Test Cost Center - _TC"
|
company.depreciation_expense_account = "_Test Depreciations - " + company.abbr
|
||||||
|
company.disposal_account = "_Test Gain/Loss on Asset Disposal - " + company.abbr
|
||||||
|
company.depreciation_cost_center = "Main - " + company.abbr
|
||||||
company.save()
|
company.save()
|
||||||
|
|
||||||
# Enable booking asset depreciation entry automatically
|
# Enable booking asset depreciation entry automatically
|
||||||
|
@ -76,7 +76,7 @@ frappe.ui.form.on('Asset Repair Consumed Item', {
|
|||||||
'warehouse': frm.doc.warehouse,
|
'warehouse': frm.doc.warehouse,
|
||||||
'qty': item.consumed_quantity,
|
'qty': item.consumed_quantity,
|
||||||
'serial_no': item.serial_no,
|
'serial_no': item.serial_no,
|
||||||
'company': frm.doc.company
|
'company': frm.doc.company,
|
||||||
};
|
};
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
|
@ -238,7 +238,6 @@
|
|||||||
"no_copy": 1
|
"no_copy": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.__islocal",
|
|
||||||
"fieldname": "purchase_invoice",
|
"fieldname": "purchase_invoice",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Purchase Invoice",
|
"label": "Purchase Invoice",
|
||||||
@ -257,6 +256,7 @@
|
|||||||
"fieldname": "stock_entry",
|
"fieldname": "stock_entry",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Stock Entry",
|
"label": "Stock Entry",
|
||||||
|
"no_copy": 1,
|
||||||
"options": "Stock Entry",
|
"options": "Stock Entry",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
}
|
}
|
||||||
@ -264,10 +264,11 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-06-25 13:14:38.307723",
|
"modified": "2022-08-16 15:55:25.023471",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Repair",
|
"name": "Asset Repair",
|
||||||
|
"naming_rule": "By \"Naming Series\" field",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@ -303,6 +304,7 @@
|
|||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"title_field": "asset_name",
|
"title_field": "asset_name",
|
||||||
"track_changes": 1,
|
"track_changes": 1,
|
||||||
"track_seen": 1
|
"track_seen": 1
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours
|
from frappe.utils import add_months, cint, flt, getdate, time_diff_in_hours
|
||||||
|
|
||||||
|
import erpnext
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
from erpnext.assets.doctype.asset.asset import get_asset_account
|
from erpnext.assets.doctype.asset.asset import get_asset_account
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
@ -17,7 +17,7 @@ class AssetRepair(AccountsController):
|
|||||||
self.update_status()
|
self.update_status()
|
||||||
|
|
||||||
if self.get("stock_items"):
|
if self.get("stock_items"):
|
||||||
self.set_total_value()
|
self.set_stock_items_cost()
|
||||||
self.calculate_total_repair_cost()
|
self.calculate_total_repair_cost()
|
||||||
|
|
||||||
def update_status(self):
|
def update_status(self):
|
||||||
@ -26,7 +26,7 @@ class AssetRepair(AccountsController):
|
|||||||
else:
|
else:
|
||||||
self.asset_doc.set_status()
|
self.asset_doc.set_status()
|
||||||
|
|
||||||
def set_total_value(self):
|
def set_stock_items_cost(self):
|
||||||
for item in self.get("stock_items"):
|
for item in self.get("stock_items"):
|
||||||
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
|
item.total_value = flt(item.valuation_rate) * flt(item.consumed_quantity)
|
||||||
|
|
||||||
@ -66,6 +66,7 @@ class AssetRepair(AccountsController):
|
|||||||
if self.get("capitalize_repair_cost"):
|
if self.get("capitalize_repair_cost"):
|
||||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
|
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry")
|
||||||
self.make_gl_entries(cancel=True)
|
self.make_gl_entries(cancel=True)
|
||||||
|
self.db_set("stock_entry", None)
|
||||||
if (
|
if (
|
||||||
frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
|
frappe.db.get_value("Asset", self.asset, "calculate_depreciation")
|
||||||
and self.increase_in_asset_life
|
and self.increase_in_asset_life
|
||||||
@ -133,6 +134,7 @@ class AssetRepair(AccountsController):
|
|||||||
"qty": stock_item.consumed_quantity,
|
"qty": stock_item.consumed_quantity,
|
||||||
"basic_rate": stock_item.valuation_rate,
|
"basic_rate": stock_item.valuation_rate,
|
||||||
"serial_no": stock_item.serial_no,
|
"serial_no": stock_item.serial_no,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -142,72 +144,42 @@ class AssetRepair(AccountsController):
|
|||||||
self.db_set("stock_entry", stock_entry.name)
|
self.db_set("stock_entry", stock_entry.name)
|
||||||
|
|
||||||
def increase_stock_quantity(self):
|
def increase_stock_quantity(self):
|
||||||
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
|
if self.stock_entry:
|
||||||
stock_entry.flags.ignore_links = True
|
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
|
||||||
stock_entry.cancel()
|
stock_entry.flags.ignore_links = True
|
||||||
|
stock_entry.cancel()
|
||||||
|
|
||||||
def make_gl_entries(self, cancel=False):
|
def make_gl_entries(self, cancel=False):
|
||||||
if flt(self.repair_cost) > 0:
|
if flt(self.total_repair_cost) > 0:
|
||||||
gl_entries = self.get_gl_entries()
|
gl_entries = self.get_gl_entries()
|
||||||
make_gl_entries(gl_entries, cancel)
|
make_gl_entries(gl_entries, cancel)
|
||||||
|
|
||||||
def get_gl_entries(self):
|
def get_gl_entries(self):
|
||||||
gl_entries = []
|
gl_entries = []
|
||||||
repair_and_maintenance_account = frappe.db.get_value(
|
|
||||||
"Company", self.company, "repair_and_maintenance_account"
|
|
||||||
)
|
|
||||||
fixed_asset_account = get_asset_account(
|
fixed_asset_account = get_asset_account(
|
||||||
"fixed_asset_account", asset=self.asset, company=self.company
|
"fixed_asset_account", asset=self.asset, company=self.company
|
||||||
)
|
)
|
||||||
expense_account = (
|
self.get_gl_entries_for_repair_cost(gl_entries, fixed_asset_account)
|
||||||
|
self.get_gl_entries_for_consumed_items(gl_entries, fixed_asset_account)
|
||||||
|
|
||||||
|
return gl_entries
|
||||||
|
|
||||||
|
def get_gl_entries_for_repair_cost(self, gl_entries, fixed_asset_account):
|
||||||
|
if flt(self.repair_cost) <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
pi_expense_account = (
|
||||||
frappe.get_doc("Purchase Invoice", self.purchase_invoice).items[0].expense_account
|
frappe.get_doc("Purchase Invoice", self.purchase_invoice).items[0].expense_account
|
||||||
)
|
)
|
||||||
|
|
||||||
gl_entries.append(
|
|
||||||
self.get_gl_dict(
|
|
||||||
{
|
|
||||||
"account": expense_account,
|
|
||||||
"credit": self.repair_cost,
|
|
||||||
"credit_in_account_currency": self.repair_cost,
|
|
||||||
"against": repair_and_maintenance_account,
|
|
||||||
"voucher_type": self.doctype,
|
|
||||||
"voucher_no": self.name,
|
|
||||||
"cost_center": self.cost_center,
|
|
||||||
"posting_date": getdate(),
|
|
||||||
"company": self.company,
|
|
||||||
},
|
|
||||||
item=self,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.get("stock_consumption"):
|
|
||||||
# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
|
|
||||||
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
|
|
||||||
for item in stock_entry.items:
|
|
||||||
gl_entries.append(
|
|
||||||
self.get_gl_dict(
|
|
||||||
{
|
|
||||||
"account": item.expense_account,
|
|
||||||
"credit": item.amount,
|
|
||||||
"credit_in_account_currency": item.amount,
|
|
||||||
"against": repair_and_maintenance_account,
|
|
||||||
"voucher_type": self.doctype,
|
|
||||||
"voucher_no": self.name,
|
|
||||||
"cost_center": self.cost_center,
|
|
||||||
"posting_date": getdate(),
|
|
||||||
"company": self.company,
|
|
||||||
},
|
|
||||||
item=self,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
gl_entries.append(
|
gl_entries.append(
|
||||||
self.get_gl_dict(
|
self.get_gl_dict(
|
||||||
{
|
{
|
||||||
"account": fixed_asset_account,
|
"account": fixed_asset_account,
|
||||||
"debit": self.total_repair_cost,
|
"debit": self.repair_cost,
|
||||||
"debit_in_account_currency": self.total_repair_cost,
|
"debit_in_account_currency": self.repair_cost,
|
||||||
"against": expense_account,
|
"against": pi_expense_account,
|
||||||
"voucher_type": self.doctype,
|
"voucher_type": self.doctype,
|
||||||
"voucher_no": self.name,
|
"voucher_no": self.name,
|
||||||
"cost_center": self.cost_center,
|
"cost_center": self.cost_center,
|
||||||
@ -220,7 +192,75 @@ class AssetRepair(AccountsController):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return gl_entries
|
gl_entries.append(
|
||||||
|
self.get_gl_dict(
|
||||||
|
{
|
||||||
|
"account": pi_expense_account,
|
||||||
|
"credit": self.repair_cost,
|
||||||
|
"credit_in_account_currency": self.repair_cost,
|
||||||
|
"against": fixed_asset_account,
|
||||||
|
"voucher_type": self.doctype,
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"posting_date": getdate(),
|
||||||
|
"company": self.company,
|
||||||
|
},
|
||||||
|
item=self,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_gl_entries_for_consumed_items(self, gl_entries, fixed_asset_account):
|
||||||
|
if not (self.get("stock_consumption") and self.get("stock_items")):
|
||||||
|
return
|
||||||
|
|
||||||
|
# creating GL Entries for each row in Stock Items based on the Stock Entry created for it
|
||||||
|
stock_entry = frappe.get_doc("Stock Entry", self.stock_entry)
|
||||||
|
|
||||||
|
default_expense_account = None
|
||||||
|
if not erpnext.is_perpetual_inventory_enabled(self.company):
|
||||||
|
default_expense_account = frappe.get_cached_value(
|
||||||
|
"Company", self.company, "default_expense_account"
|
||||||
|
)
|
||||||
|
if not default_expense_account:
|
||||||
|
frappe.throw(_("Please set default Expense Account in Company {0}").format(self.company))
|
||||||
|
|
||||||
|
for item in stock_entry.items:
|
||||||
|
if flt(item.amount) > 0:
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict(
|
||||||
|
{
|
||||||
|
"account": item.expense_account or default_expense_account,
|
||||||
|
"credit": item.amount,
|
||||||
|
"credit_in_account_currency": item.amount,
|
||||||
|
"against": fixed_asset_account,
|
||||||
|
"voucher_type": self.doctype,
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"posting_date": getdate(),
|
||||||
|
"company": self.company,
|
||||||
|
},
|
||||||
|
item=self,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict(
|
||||||
|
{
|
||||||
|
"account": fixed_asset_account,
|
||||||
|
"debit": item.amount,
|
||||||
|
"debit_in_account_currency": item.amount,
|
||||||
|
"against": item.expense_account or default_expense_account,
|
||||||
|
"voucher_type": self.doctype,
|
||||||
|
"voucher_no": self.name,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"posting_date": getdate(),
|
||||||
|
"against_voucher_type": "Stock Entry",
|
||||||
|
"against_voucher": self.stock_entry,
|
||||||
|
"company": self.company,
|
||||||
|
},
|
||||||
|
item=self,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def modify_depreciation_schedule(self):
|
def modify_depreciation_schedule(self):
|
||||||
for row in self.asset_doc.finance_books:
|
for row in self.asset_doc.finance_books:
|
||||||
|
@ -6,6 +6,7 @@ import unittest
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt, nowdate
|
from frappe.utils import flt, nowdate
|
||||||
|
|
||||||
|
from erpnext.assets.doctype.asset.asset import get_asset_account
|
||||||
from erpnext.assets.doctype.asset.test_asset import (
|
from erpnext.assets.doctype.asset.test_asset import (
|
||||||
create_asset,
|
create_asset,
|
||||||
create_asset_data,
|
create_asset_data,
|
||||||
@ -125,10 +126,109 @@ class TestAssetRepair(unittest.TestCase):
|
|||||||
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
|
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
|
||||||
self.assertTrue(asset_repair.purchase_invoice)
|
self.assertTrue(asset_repair.purchase_invoice)
|
||||||
|
|
||||||
def test_gl_entries(self):
|
def test_gl_entries_with_perpetual_inventory(self):
|
||||||
asset_repair = create_asset_repair(capitalize_repair_cost=1, submit=1)
|
set_depreciation_settings_in_company(company="_Test Company with perpetual inventory")
|
||||||
gl_entry = frappe.get_last_doc("GL Entry")
|
|
||||||
self.assertEqual(asset_repair.name, gl_entry.voucher_no)
|
asset_category = frappe.get_doc("Asset Category", "Computers")
|
||||||
|
asset_category.append(
|
||||||
|
"accounts",
|
||||||
|
{
|
||||||
|
"company_name": "_Test Company with perpetual inventory",
|
||||||
|
"fixed_asset_account": "_Test Fixed Asset - TCP1",
|
||||||
|
"accumulated_depreciation_account": "_Test Accumulated Depreciations - TCP1",
|
||||||
|
"depreciation_expense_account": "_Test Depreciations - TCP1",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
asset_category.save()
|
||||||
|
|
||||||
|
asset_repair = create_asset_repair(
|
||||||
|
capitalize_repair_cost=1,
|
||||||
|
stock_consumption=1,
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
company="_Test Company with perpetual inventory",
|
||||||
|
submit=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
account,
|
||||||
|
sum(debit) as debit,
|
||||||
|
sum(credit) as credit
|
||||||
|
from `tabGL Entry`
|
||||||
|
where
|
||||||
|
voucher_type='Asset Repair'
|
||||||
|
and voucher_no=%s
|
||||||
|
group by
|
||||||
|
account
|
||||||
|
""",
|
||||||
|
asset_repair.name,
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
|
fixed_asset_account = get_asset_account(
|
||||||
|
"fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
|
||||||
|
)
|
||||||
|
pi_expense_account = (
|
||||||
|
frappe.get_doc("Purchase Invoice", asset_repair.purchase_invoice).items[0].expense_account
|
||||||
|
)
|
||||||
|
stock_entry_expense_account = (
|
||||||
|
frappe.get_doc("Stock Entry", asset_repair.stock_entry).get("items")[0].expense_account
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_values = {
|
||||||
|
fixed_asset_account: [asset_repair.total_repair_cost, 0],
|
||||||
|
pi_expense_account: [0, asset_repair.repair_cost],
|
||||||
|
stock_entry_expense_account: [0, 100],
|
||||||
|
}
|
||||||
|
|
||||||
|
for d in gl_entries:
|
||||||
|
self.assertEqual(expected_values[d.account][0], d.debit)
|
||||||
|
self.assertEqual(expected_values[d.account][1], d.credit)
|
||||||
|
|
||||||
|
def test_gl_entries_with_periodical_inventory(self):
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Company", "_Test Company", "default_expense_account", "Cost of Goods Sold - _TC"
|
||||||
|
)
|
||||||
|
asset_repair = create_asset_repair(
|
||||||
|
capitalize_repair_cost=1,
|
||||||
|
stock_consumption=1,
|
||||||
|
submit=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
account,
|
||||||
|
sum(debit) as debit,
|
||||||
|
sum(credit) as credit
|
||||||
|
from `tabGL Entry`
|
||||||
|
where
|
||||||
|
voucher_type='Asset Repair'
|
||||||
|
and voucher_no=%s
|
||||||
|
group by
|
||||||
|
account
|
||||||
|
""",
|
||||||
|
asset_repair.name,
|
||||||
|
as_dict=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
|
fixed_asset_account = get_asset_account(
|
||||||
|
"fixed_asset_account", asset=asset_repair.asset, company=asset_repair.company
|
||||||
|
)
|
||||||
|
default_expense_account = frappe.get_cached_value(
|
||||||
|
"Company", asset_repair.company, "default_expense_account"
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_values = {fixed_asset_account: [1100, 0], default_expense_account: [0, 1100]}
|
||||||
|
|
||||||
|
for d in gl_entries:
|
||||||
|
self.assertEqual(expected_values[d.account][0], d.debit)
|
||||||
|
self.assertEqual(expected_values[d.account][1], d.credit)
|
||||||
|
|
||||||
def test_increase_in_asset_life(self):
|
def test_increase_in_asset_life(self):
|
||||||
asset = create_asset(calculate_depreciation=1, submit=1)
|
asset = create_asset(calculate_depreciation=1, submit=1)
|
||||||
@ -160,7 +260,7 @@ def create_asset_repair(**args):
|
|||||||
if args.asset:
|
if args.asset:
|
||||||
asset = args.asset
|
asset = args.asset
|
||||||
else:
|
else:
|
||||||
asset = create_asset(is_existing_asset=1, submit=1)
|
asset = create_asset(is_existing_asset=1, submit=1, company=args.company)
|
||||||
asset_repair = frappe.new_doc("Asset Repair")
|
asset_repair = frappe.new_doc("Asset Repair")
|
||||||
asset_repair.update(
|
asset_repair.update(
|
||||||
{
|
{
|
||||||
@ -192,7 +292,7 @@ def create_asset_repair(**args):
|
|||||||
|
|
||||||
if args.submit:
|
if args.submit:
|
||||||
asset_repair.repair_status = "Completed"
|
asset_repair.repair_status = "Completed"
|
||||||
asset_repair.cost_center = "_Test Cost Center - _TC"
|
asset_repair.cost_center = frappe.db.get_value("Company", asset.company, "cost_center")
|
||||||
|
|
||||||
if args.stock_consumption:
|
if args.stock_consumption:
|
||||||
stock_entry = frappe.get_doc(
|
stock_entry = frappe.get_doc(
|
||||||
@ -204,6 +304,8 @@ def create_asset_repair(**args):
|
|||||||
"t_warehouse": asset_repair.warehouse,
|
"t_warehouse": asset_repair.warehouse,
|
||||||
"item_code": asset_repair.stock_items[0].item_code,
|
"item_code": asset_repair.stock_items[0].item_code,
|
||||||
"qty": asset_repair.stock_items[0].consumed_quantity,
|
"qty": asset_repair.stock_items[0].consumed_quantity,
|
||||||
|
"basic_rate": args.rate if args.get("rate") is not None else 100,
|
||||||
|
"cost_center": asset_repair.cost_center,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
stock_entry.submit()
|
stock_entry.submit()
|
||||||
@ -213,7 +315,13 @@ def create_asset_repair(**args):
|
|||||||
asset_repair.repair_cost = 1000
|
asset_repair.repair_cost = 1000
|
||||||
if asset.calculate_depreciation:
|
if asset.calculate_depreciation:
|
||||||
asset_repair.increase_in_asset_life = 12
|
asset_repair.increase_in_asset_life = 12
|
||||||
asset_repair.purchase_invoice = make_purchase_invoice().name
|
pi = make_purchase_invoice(
|
||||||
|
company=asset.company,
|
||||||
|
expense_account=frappe.db.get_value("Company", asset.company, "default_expense_account"),
|
||||||
|
cost_center=asset_repair.cost_center,
|
||||||
|
warehouse=asset_repair.warehouse,
|
||||||
|
)
|
||||||
|
asset_repair.purchase_invoice = pi.name
|
||||||
|
|
||||||
asset_repair.submit()
|
asset_repair.submit()
|
||||||
return asset_repair
|
return asset_repair
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
"label": "Subcontracting Settings"
|
"label": "Subcontracting Settings"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Material Transferred for Subcontract",
|
"default": "BOM",
|
||||||
"fieldname": "backflush_raw_materials_of_subcontract_based_on",
|
"fieldname": "backflush_raw_materials_of_subcontract_based_on",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Backflush Raw Materials of Subcontract Based On",
|
"label": "Backflush Raw Materials of Subcontract Based On",
|
||||||
@ -148,7 +148,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-05-31 19:40:26.103909",
|
"modified": "2022-09-01 18:01:34.994657",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Buying Settings",
|
"name": "Buying Settings",
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
"section_break_45",
|
"section_break_45",
|
||||||
"before_items_section",
|
"before_items_section",
|
||||||
"scan_barcode",
|
"scan_barcode",
|
||||||
|
"set_from_warehouse",
|
||||||
"items_col_break",
|
"items_col_break",
|
||||||
"set_warehouse",
|
"set_warehouse",
|
||||||
"items_section",
|
"items_section",
|
||||||
@ -1166,13 +1167,20 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Is Old Subcontracting Flow",
|
"label": "Is Old Subcontracting Flow",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "is_internal_supplier",
|
||||||
|
"fieldname": "set_from_warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Set From Warehouse",
|
||||||
|
"options": "Warehouse"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-file-text",
|
"icon": "fa fa-file-text",
|
||||||
"idx": 105,
|
"idx": 105,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-15 15:40:58.527065",
|
"modified": "2022-09-07 11:06:46.035093",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order",
|
"name": "Purchase Order",
|
||||||
|
@ -23,5 +23,6 @@ def get_data():
|
|||||||
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
|
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
|
||||||
},
|
},
|
||||||
{"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]},
|
{"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]},
|
||||||
|
{"label": _("Internal"), "items": ["Sales Order"]},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@ import json
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import add_days, flt, getdate, nowdate
|
from frappe.utils import add_days, flt, getdate, nowdate
|
||||||
|
from frappe.utils.data import today
|
||||||
|
|
||||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
|
from erpnext.buying.doctype.purchase_order.purchase_order import make_inter_company_sales_order
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import (
|
from erpnext.buying.doctype.purchase_order.purchase_order import (
|
||||||
make_purchase_invoice as make_pi_from_po,
|
make_purchase_invoice as make_pi_from_po,
|
||||||
)
|
)
|
||||||
@ -796,6 +798,111 @@ class TestPurchaseOrder(FrappeTestCase):
|
|||||||
|
|
||||||
automatically_fetch_payment_terms(enable=0)
|
automatically_fetch_payment_terms(enable=0)
|
||||||
|
|
||||||
|
def test_internal_transfer_flow(self):
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
|
||||||
|
make_inter_company_purchase_invoice,
|
||||||
|
)
|
||||||
|
from erpnext.selling.doctype.sales_order.sales_order import (
|
||||||
|
make_delivery_note,
|
||||||
|
make_sales_invoice,
|
||||||
|
)
|
||||||
|
from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
|
||||||
|
|
||||||
|
frappe.db.set_value("Selling Settings", None, "maintain_same_sales_rate", 1)
|
||||||
|
frappe.db.set_value("Buying Settings", None, "maintain_same_rate", 1)
|
||||||
|
|
||||||
|
prepare_data_for_internal_transfer()
|
||||||
|
supplier = "_Test Internal Supplier 2"
|
||||||
|
|
||||||
|
po = create_purchase_order(
|
||||||
|
company="_Test Company with perpetual inventory",
|
||||||
|
supplier=supplier,
|
||||||
|
warehouse="Stores - TCP1",
|
||||||
|
from_warehouse="_Test Internal Warehouse New 1 - TCP1",
|
||||||
|
qty=2,
|
||||||
|
rate=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
so = make_inter_company_sales_order(po.name)
|
||||||
|
so.items[0].delivery_date = today()
|
||||||
|
self.assertEqual(so.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1")
|
||||||
|
self.assertTrue(so.items[0].purchase_order)
|
||||||
|
self.assertTrue(so.items[0].purchase_order_item)
|
||||||
|
so.submit()
|
||||||
|
|
||||||
|
dn = make_delivery_note(so.name)
|
||||||
|
dn.items[0].target_warehouse = "_Test Internal Warehouse GIT - TCP1"
|
||||||
|
self.assertEqual(dn.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1")
|
||||||
|
self.assertTrue(dn.items[0].purchase_order)
|
||||||
|
self.assertTrue(dn.items[0].purchase_order_item)
|
||||||
|
|
||||||
|
self.assertEqual(po.items[0].name, dn.items[0].purchase_order_item)
|
||||||
|
dn.submit()
|
||||||
|
|
||||||
|
pr = make_inter_company_purchase_receipt(dn.name)
|
||||||
|
self.assertEqual(pr.items[0].warehouse, "Stores - TCP1")
|
||||||
|
self.assertTrue(pr.items[0].purchase_order)
|
||||||
|
self.assertTrue(pr.items[0].purchase_order_item)
|
||||||
|
self.assertEqual(po.items[0].name, pr.items[0].purchase_order_item)
|
||||||
|
pr.submit()
|
||||||
|
|
||||||
|
si = make_sales_invoice(so.name)
|
||||||
|
self.assertEqual(si.items[0].warehouse, "_Test Internal Warehouse New 1 - TCP1")
|
||||||
|
self.assertTrue(si.items[0].purchase_order)
|
||||||
|
self.assertTrue(si.items[0].purchase_order_item)
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
pi = make_inter_company_purchase_invoice(si.name)
|
||||||
|
self.assertTrue(pi.items[0].purchase_order)
|
||||||
|
self.assertTrue(pi.items[0].po_detail)
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
po.load_from_db()
|
||||||
|
self.assertEqual(po.status, "Completed")
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_data_for_internal_transfer():
|
||||||
|
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
|
||||||
|
from erpnext.selling.doctype.customer.test_customer import create_internal_customer
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
|
||||||
|
company = "_Test Company with perpetual inventory"
|
||||||
|
|
||||||
|
create_internal_customer(
|
||||||
|
"_Test Internal Customer 2",
|
||||||
|
company,
|
||||||
|
company,
|
||||||
|
)
|
||||||
|
|
||||||
|
create_internal_supplier(
|
||||||
|
"_Test Internal Supplier 2",
|
||||||
|
company,
|
||||||
|
company,
|
||||||
|
)
|
||||||
|
|
||||||
|
warehouse = create_warehouse("_Test Internal Warehouse New 1", company=company)
|
||||||
|
|
||||||
|
create_warehouse("_Test Internal Warehouse GIT", company=company)
|
||||||
|
|
||||||
|
make_purchase_receipt(company=company, warehouse=warehouse, qty=2, rate=100)
|
||||||
|
|
||||||
|
if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"):
|
||||||
|
account = "Unrealized Profit and Loss - TCP1"
|
||||||
|
if not frappe.db.exists("Account", account):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Account",
|
||||||
|
"account_name": "Unrealized Profit and Loss",
|
||||||
|
"parent_account": "Direct Income - TCP1",
|
||||||
|
"company": company,
|
||||||
|
"is_group": 0,
|
||||||
|
"account_type": "Income Account",
|
||||||
|
}
|
||||||
|
).insert()
|
||||||
|
|
||||||
|
frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account)
|
||||||
|
|
||||||
|
|
||||||
def make_pr_against_po(po, received_qty=0):
|
def make_pr_against_po(po, received_qty=0):
|
||||||
pr = make_purchase_receipt(po)
|
pr = make_purchase_receipt(po)
|
||||||
@ -847,6 +954,7 @@ def create_purchase_order(**args):
|
|||||||
{
|
{
|
||||||
"item_code": args.item or args.item_code or "_Test Item",
|
"item_code": args.item or args.item_code or "_Test Item",
|
||||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||||
|
"from_warehouse": args.from_warehouse,
|
||||||
"qty": args.qty or 10,
|
"qty": args.qty or 10,
|
||||||
"rate": args.rate or 500,
|
"rate": args.rate or 500,
|
||||||
"schedule_date": add_days(nowdate(), 1),
|
"schedule_date": add_days(nowdate(), 1),
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
"item_code",
|
"item_code",
|
||||||
"supplier_part_no",
|
"supplier_part_no",
|
||||||
"item_name",
|
"item_name",
|
||||||
|
"brand",
|
||||||
"product_bundle",
|
"product_bundle",
|
||||||
"fg_item",
|
"fg_item",
|
||||||
"fg_item_qty",
|
"fg_item_qty",
|
||||||
"column_break_4",
|
"column_break_4",
|
||||||
"schedule_date",
|
"schedule_date",
|
||||||
"expected_delivery_date",
|
"expected_delivery_date",
|
||||||
|
"item_group",
|
||||||
"section_break_5",
|
"section_break_5",
|
||||||
"description",
|
"description",
|
||||||
"col_break1",
|
"col_break1",
|
||||||
@ -58,9 +60,12 @@
|
|||||||
"base_net_rate",
|
"base_net_rate",
|
||||||
"base_net_amount",
|
"base_net_amount",
|
||||||
"warehouse_and_reference",
|
"warehouse_and_reference",
|
||||||
|
"from_warehouse",
|
||||||
"warehouse",
|
"warehouse",
|
||||||
|
"column_break_54",
|
||||||
"actual_qty",
|
"actual_qty",
|
||||||
"company_total_stock",
|
"company_total_stock",
|
||||||
|
"references_section",
|
||||||
"material_request",
|
"material_request",
|
||||||
"material_request_item",
|
"material_request_item",
|
||||||
"sales_order",
|
"sales_order",
|
||||||
@ -73,8 +78,6 @@
|
|||||||
"against_blanket_order",
|
"against_blanket_order",
|
||||||
"blanket_order",
|
"blanket_order",
|
||||||
"blanket_order_rate",
|
"blanket_order_rate",
|
||||||
"item_group",
|
|
||||||
"brand",
|
|
||||||
"section_break_56",
|
"section_break_56",
|
||||||
"received_qty",
|
"received_qty",
|
||||||
"returned_qty",
|
"returned_qty",
|
||||||
@ -442,13 +445,13 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "warehouse_and_reference",
|
"fieldname": "warehouse_and_reference",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Warehouse and Reference"
|
"label": "Warehouse Settings"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "warehouse",
|
"fieldname": "warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Warehouse",
|
"label": "Target Warehouse",
|
||||||
"oldfieldname": "warehouse",
|
"oldfieldname": "warehouse",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Warehouse",
|
"options": "Warehouse",
|
||||||
@ -760,7 +763,7 @@
|
|||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"fieldname": "actual_qty",
|
"fieldname": "actual_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Available Qty at Warehouse",
|
"label": "Available Qty at Target Warehouse",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -868,13 +871,30 @@
|
|||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Finished Good Item Qty",
|
"label": "Finished Good Item Qty",
|
||||||
"mandatory_depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow"
|
"mandatory_depends_on": "eval:parent.is_subcontracted && !parent.is_old_subcontracting_flow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:parent.is_internal_supplier",
|
||||||
|
"fieldname": "from_warehouse",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "From Warehouse",
|
||||||
|
"options": "Warehouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "references_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "References"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_54",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-17 05:29:40.602349",
|
"modified": "2022-09-07 11:12:38.634976",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
@ -373,7 +373,7 @@ class AccountsController(TransactionBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def validate_inter_company_reference(self):
|
def validate_inter_company_reference(self):
|
||||||
if self.doctype not in ("Purchase Invoice", "Purchase Receipt", "Purchase Order"):
|
if self.doctype not in ("Purchase Invoice", "Purchase Receipt"):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.is_internal_transfer():
|
if self.is_internal_transfer():
|
||||||
@ -1109,17 +1109,17 @@ class AccountsController(TransactionBase):
|
|||||||
frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
|
frappe.db.get_single_value("Selling Settings", "enable_discount_accounting")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.doctype == "Purchase Invoice":
|
||||||
|
dr_or_cr = "credit"
|
||||||
|
rev_dr_cr = "debit"
|
||||||
|
supplier_or_customer = self.supplier
|
||||||
|
|
||||||
|
else:
|
||||||
|
dr_or_cr = "debit"
|
||||||
|
rev_dr_cr = "credit"
|
||||||
|
supplier_or_customer = self.customer
|
||||||
|
|
||||||
if enable_discount_accounting:
|
if enable_discount_accounting:
|
||||||
if self.doctype == "Purchase Invoice":
|
|
||||||
dr_or_cr = "credit"
|
|
||||||
rev_dr_cr = "debit"
|
|
||||||
supplier_or_customer = self.supplier
|
|
||||||
|
|
||||||
else:
|
|
||||||
dr_or_cr = "debit"
|
|
||||||
rev_dr_cr = "credit"
|
|
||||||
supplier_or_customer = self.customer
|
|
||||||
|
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if item.get("discount_amount") and item.get("discount_account"):
|
if item.get("discount_amount") and item.get("discount_account"):
|
||||||
discount_amount = item.discount_amount * item.qty
|
discount_amount = item.discount_amount * item.qty
|
||||||
@ -1173,18 +1173,22 @@ class AccountsController(TransactionBase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.get("discount_amount") and self.get("additional_discount_account"):
|
if (
|
||||||
gl_entries.append(
|
(enable_discount_accounting or self.get("is_cash_or_non_trade_discount"))
|
||||||
self.get_gl_dict(
|
and self.get("additional_discount_account")
|
||||||
{
|
and self.get("discount_amount")
|
||||||
"account": self.additional_discount_account,
|
):
|
||||||
"against": supplier_or_customer,
|
gl_entries.append(
|
||||||
dr_or_cr: self.discount_amount,
|
self.get_gl_dict(
|
||||||
"cost_center": self.cost_center,
|
{
|
||||||
},
|
"account": self.additional_discount_account,
|
||||||
item=self,
|
"against": supplier_or_customer,
|
||||||
)
|
dr_or_cr: self.discount_amount,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
},
|
||||||
|
item=self,
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
|
||||||
from erpnext.controllers.status_updater import get_allowance_for
|
from erpnext.controllers.status_updater import get_allowance_for
|
||||||
|
@ -311,6 +311,7 @@ class SellingController(StockController):
|
|||||||
"sales_invoice_item": d.get("sales_invoice_item"),
|
"sales_invoice_item": d.get("sales_invoice_item"),
|
||||||
"dn_detail": d.get("dn_detail"),
|
"dn_detail": d.get("dn_detail"),
|
||||||
"incoming_rate": p.get("incoming_rate"),
|
"incoming_rate": p.get("incoming_rate"),
|
||||||
|
"item_row": p,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -334,6 +335,7 @@ class SellingController(StockController):
|
|||||||
"sales_invoice_item": d.get("sales_invoice_item"),
|
"sales_invoice_item": d.get("sales_invoice_item"),
|
||||||
"dn_detail": d.get("dn_detail"),
|
"dn_detail": d.get("dn_detail"),
|
||||||
"incoming_rate": d.get("incoming_rate"),
|
"incoming_rate": d.get("incoming_rate"),
|
||||||
|
"item_row": d,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -307,6 +307,20 @@ class StatusUpdater(Document):
|
|||||||
|
|
||||||
def limits_crossed_error(self, args, item, qty_or_amount):
|
def limits_crossed_error(self, args, item, qty_or_amount):
|
||||||
"""Raise exception for limits crossed"""
|
"""Raise exception for limits crossed"""
|
||||||
|
if (
|
||||||
|
self.doctype in ["Sales Invoice", "Delivery Note"]
|
||||||
|
and qty_or_amount == "amount"
|
||||||
|
and self.is_internal_customer
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
elif (
|
||||||
|
self.doctype in ["Purchase Invoice", "Purchase Receipt"]
|
||||||
|
and qty_or_amount == "amount"
|
||||||
|
and self.is_internal_supplier
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
if qty_or_amount == "qty":
|
if qty_or_amount == "qty":
|
||||||
action_msg = _(
|
action_msg = _(
|
||||||
'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.'
|
'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.'
|
||||||
|
@ -390,6 +390,10 @@ class StockController(AccountsController):
|
|||||||
return sl_dict
|
return sl_dict
|
||||||
|
|
||||||
def update_inventory_dimensions(self, row, sl_dict) -> None:
|
def update_inventory_dimensions(self, row, sl_dict) -> None:
|
||||||
|
# To handle delivery note and sales invoice
|
||||||
|
if row.get("item_row"):
|
||||||
|
row = row.get("item_row")
|
||||||
|
|
||||||
dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self)
|
dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self)
|
||||||
for dimension in dimensions:
|
for dimension in dimensions:
|
||||||
if not dimension:
|
if not dimension:
|
||||||
@ -407,9 +411,17 @@ class StockController(AccountsController):
|
|||||||
"DocField", {"parent": self.doctype, "options": dimension.fetch_from_parent}, "fieldname"
|
"DocField", {"parent": self.doctype, "options": dimension.fetch_from_parent}, "fieldname"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not fieldname:
|
||||||
|
fieldname = frappe.get_cached_value(
|
||||||
|
"Custom Field", {"dt": self.doctype, "options": dimension.fetch_from_parent}, "fieldname"
|
||||||
|
)
|
||||||
|
|
||||||
if fieldname and self.get(fieldname):
|
if fieldname and self.get(fieldname):
|
||||||
sl_dict[dimension.target_fieldname] = self.get(fieldname)
|
sl_dict[dimension.target_fieldname] = self.get(fieldname)
|
||||||
|
|
||||||
|
if sl_dict[dimension.target_fieldname] and self.docstatus == 1:
|
||||||
|
row.db_set(dimension.source_fieldname, sl_dict[dimension.target_fieldname])
|
||||||
|
|
||||||
def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
|
def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
|
||||||
from erpnext.stock.stock_ledger import make_sl_entries
|
from erpnext.stock.stock_ledger import make_sl_entries
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from collections import defaultdict
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.utils import cint, cstr, flt, get_link_to_form
|
from frappe.utils import cint, cstr, flt, get_link_to_form
|
||||||
|
|
||||||
from erpnext.controllers.stock_controller import StockController
|
from erpnext.controllers.stock_controller import StockController
|
||||||
@ -870,7 +871,17 @@ def add_items_in_ste(
|
|||||||
def make_return_stock_entry_for_subcontract(
|
def make_return_stock_entry_for_subcontract(
|
||||||
available_materials, order_doc, rm_details, order_doctype="Subcontracting Order"
|
available_materials, order_doc, rm_details, order_doctype="Subcontracting Order"
|
||||||
):
|
):
|
||||||
ste_doc = frappe.new_doc("Stock Entry")
|
ste_doc = get_mapped_doc(
|
||||||
|
order_doctype,
|
||||||
|
order_doc.name,
|
||||||
|
{
|
||||||
|
order_doctype: {
|
||||||
|
"doctype": "Stock Entry",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ignore_child_tables=True,
|
||||||
|
)
|
||||||
|
|
||||||
ste_doc.purpose = "Material Transfer"
|
ste_doc.purpose = "Material Transfer"
|
||||||
|
|
||||||
if order_doctype == "Purchase Order":
|
if order_doctype == "Purchase Order":
|
||||||
|
@ -37,6 +37,12 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.set_discount_amount()
|
self.set_discount_amount()
|
||||||
self.apply_discount_amount()
|
self.apply_discount_amount()
|
||||||
|
|
||||||
|
# Update grand total as per cash and non trade discount
|
||||||
|
if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
|
||||||
|
self.doc.grand_total -= self.doc.discount_amount
|
||||||
|
self.doc.base_grand_total -= self.doc.base_discount_amount
|
||||||
|
self.set_rounded_total()
|
||||||
|
|
||||||
self.calculate_shipping_charges()
|
self.calculate_shipping_charges()
|
||||||
|
|
||||||
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
if self.doc.doctype in ["Sales Invoice", "Purchase Invoice"]:
|
||||||
@ -500,9 +506,6 @@ class calculate_taxes_and_totals(object):
|
|||||||
else:
|
else:
|
||||||
self.doc.grand_total = flt(self.doc.net_total)
|
self.doc.grand_total = flt(self.doc.net_total)
|
||||||
|
|
||||||
if self.doc.apply_discount_on == "Grand Total" and self.doc.get("is_cash_or_non_trade_discount"):
|
|
||||||
self.doc.grand_total -= self.doc.discount_amount
|
|
||||||
|
|
||||||
if self.doc.get("taxes"):
|
if self.doc.get("taxes"):
|
||||||
self.doc.total_taxes_and_charges = flt(
|
self.doc.total_taxes_and_charges = flt(
|
||||||
self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
|
self.doc.grand_total - self.doc.net_total - flt(self.doc.rounding_adjustment),
|
||||||
@ -597,16 +600,16 @@ class calculate_taxes_and_totals(object):
|
|||||||
if not self.doc.apply_discount_on:
|
if not self.doc.apply_discount_on:
|
||||||
frappe.throw(_("Please select Apply Discount On"))
|
frappe.throw(_("Please select Apply Discount On"))
|
||||||
|
|
||||||
|
self.doc.base_discount_amount = flt(
|
||||||
|
self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
|
||||||
|
)
|
||||||
|
|
||||||
if self.doc.apply_discount_on == "Grand Total" and self.doc.get(
|
if self.doc.apply_discount_on == "Grand Total" and self.doc.get(
|
||||||
"is_cash_or_non_trade_discount"
|
"is_cash_or_non_trade_discount"
|
||||||
):
|
):
|
||||||
self.discount_amount_applied = True
|
self.discount_amount_applied = True
|
||||||
return
|
return
|
||||||
|
|
||||||
self.doc.base_discount_amount = flt(
|
|
||||||
self.doc.discount_amount * self.doc.conversion_rate, self.doc.precision("base_discount_amount")
|
|
||||||
)
|
|
||||||
|
|
||||||
total_for_discount_amount = self.get_total_for_discount_amount()
|
total_for_discount_amount = self.get_total_for_discount_amount()
|
||||||
taxes = self.doc.get("taxes")
|
taxes = self.doc.get("taxes")
|
||||||
net_total = 0
|
net_total = 0
|
||||||
@ -767,6 +770,18 @@ class calculate_taxes_and_totals(object):
|
|||||||
self.doc.precision("outstanding_amount"),
|
self.doc.precision("outstanding_amount"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.doc.doctype == "Sales Invoice"
|
||||||
|
and self.doc.get("is_pos")
|
||||||
|
and self.doc.get("pos_profile")
|
||||||
|
and self.doc.get("is_consolidated")
|
||||||
|
):
|
||||||
|
write_off_limit = flt(
|
||||||
|
frappe.db.get_value("POS Profile", self.doc.pos_profile, "write_off_limit")
|
||||||
|
)
|
||||||
|
if write_off_limit and abs(self.doc.outstanding_amount) <= write_off_limit:
|
||||||
|
self.doc.write_off_outstanding_amount_automatically = 1
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.doc.doctype == "Sales Invoice"
|
self.doc.doctype == "Sales Invoice"
|
||||||
and self.doc.get("is_pos")
|
and self.doc.get("is_pos")
|
||||||
|
@ -7,7 +7,7 @@ from collections import Counter
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import get_url, getdate
|
from frappe.utils import get_url, getdate, now
|
||||||
from frappe.utils.verified_command import get_signed_params
|
from frappe.utils.verified_command import get_signed_params
|
||||||
|
|
||||||
|
|
||||||
@ -104,16 +104,28 @@ class Appointment(Document):
|
|||||||
# Return if already linked
|
# Return if already linked
|
||||||
if self.party:
|
if self.party:
|
||||||
return
|
return
|
||||||
|
|
||||||
lead = frappe.get_doc(
|
lead = frappe.get_doc(
|
||||||
{
|
{
|
||||||
"doctype": "Lead",
|
"doctype": "Lead",
|
||||||
"lead_name": self.customer_name,
|
"lead_name": self.customer_name,
|
||||||
"email_id": self.customer_email,
|
"email_id": self.customer_email,
|
||||||
"notes": self.customer_details,
|
|
||||||
"phone": self.customer_phone_number,
|
"phone": self.customer_phone_number,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.customer_details:
|
||||||
|
lead.append(
|
||||||
|
"notes",
|
||||||
|
{
|
||||||
|
"note": self.customer_details,
|
||||||
|
"added_by": frappe.session.user,
|
||||||
|
"added_on": now(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
lead.insert(ignore_permissions=True)
|
lead.insert(ignore_permissions=True)
|
||||||
|
|
||||||
# Link lead
|
# Link lead
|
||||||
self.party = lead.name
|
self.party = lead.name
|
||||||
|
|
||||||
|
@ -6,29 +6,20 @@ import unittest
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
|
LEAD_EMAIL = "test_appointment_lead@example.com"
|
||||||
def create_test_lead():
|
|
||||||
test_lead = frappe.db.get_value("Lead", {"email_id": "test@example.com"})
|
|
||||||
if test_lead:
|
|
||||||
return frappe.get_doc("Lead", test_lead)
|
|
||||||
test_lead = frappe.get_doc(
|
|
||||||
{"doctype": "Lead", "lead_name": "Test Lead", "email_id": "test@example.com"}
|
|
||||||
)
|
|
||||||
test_lead.insert(ignore_permissions=True)
|
|
||||||
return test_lead
|
|
||||||
|
|
||||||
|
|
||||||
def create_test_appointments():
|
def create_test_appointment():
|
||||||
test_appointment = frappe.get_doc(
|
test_appointment = frappe.get_doc(
|
||||||
{
|
{
|
||||||
"doctype": "Appointment",
|
"doctype": "Appointment",
|
||||||
"email": "test@example.com",
|
|
||||||
"status": "Open",
|
"status": "Open",
|
||||||
"customer_name": "Test Lead",
|
"customer_name": "Test Lead",
|
||||||
"customer_phone_number": "666",
|
"customer_phone_number": "666",
|
||||||
"customer_skype": "test",
|
"customer_skype": "test",
|
||||||
"customer_email": "test@example.com",
|
"customer_email": LEAD_EMAIL,
|
||||||
"scheduled_time": datetime.datetime.now(),
|
"scheduled_time": datetime.datetime.now(),
|
||||||
|
"customer_details": "Hello, Friend!",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
test_appointment.insert()
|
test_appointment.insert()
|
||||||
@ -36,16 +27,16 @@ def create_test_appointments():
|
|||||||
|
|
||||||
|
|
||||||
class TestAppointment(unittest.TestCase):
|
class TestAppointment(unittest.TestCase):
|
||||||
test_appointment = test_lead = None
|
def setUpClass():
|
||||||
|
frappe.db.delete("Lead", {"email_id": LEAD_EMAIL})
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.test_lead = create_test_lead()
|
self.test_appointment = create_test_appointment()
|
||||||
self.test_appointment = create_test_appointments()
|
self.test_appointment.set_verified(self.test_appointment.customer_email)
|
||||||
|
|
||||||
def test_calendar_event_created(self):
|
def test_calendar_event_created(self):
|
||||||
cal_event = frappe.get_doc("Event", self.test_appointment.calendar_event)
|
cal_event = frappe.get_doc("Event", self.test_appointment.calendar_event)
|
||||||
self.assertEqual(cal_event.starts_on, self.test_appointment.scheduled_time)
|
self.assertEqual(cal_event.starts_on, self.test_appointment.scheduled_time)
|
||||||
|
|
||||||
def test_lead_linked(self):
|
def test_lead_linked(self):
|
||||||
lead = frappe.get_doc("Lead", self.test_lead.name)
|
self.assertTrue(self.test_appointment.party)
|
||||||
self.assertIsNotNone(lead)
|
|
||||||
|
@ -200,7 +200,7 @@ erpnext.ProductSearch = class {
|
|||||||
let thumbnail = res.thumbnail || '/assets/erpnext/images/ui-states/cart-empty-state.png';
|
let thumbnail = res.thumbnail || '/assets/erpnext/images/ui-states/cart-empty-state.png';
|
||||||
html += `
|
html += `
|
||||||
<div class="dropdown-item" style="display: flex;">
|
<div class="dropdown-item" style="display: flex;">
|
||||||
<img class="item-thumb col-2" src=${thumbnail} />
|
<img class="item-thumb col-2" src=${encodeURI(thumbnail)} />
|
||||||
<div class="col-9" style="white-space: normal;">
|
<div class="col-9" style="white-space: normal;">
|
||||||
<a href="/${res.route}">${res.web_item_name}</a><br>
|
<a href="/${res.route}">${res.web_item_name}</a><br>
|
||||||
<span class="brand-line">${res.brand ? "by " + res.brand : ""}</span>
|
<span class="brand-line">${res.brand ? "by " + res.brand : ""}</span>
|
||||||
|
@ -7,7 +7,9 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils.redis_wrapper import RedisWrapper
|
from frappe.utils.redis_wrapper import RedisWrapper
|
||||||
from redis import ResponseError
|
from redis import ResponseError
|
||||||
from redisearch import AutoCompleter, Client, IndexDefinition, Suggestion, TagField, TextField
|
from redis.commands.search.field import TagField, TextField
|
||||||
|
from redis.commands.search.indexDefinition import IndexDefinition
|
||||||
|
from redis.commands.search.suggestion import Suggestion
|
||||||
|
|
||||||
WEBSITE_ITEM_INDEX = "website_items_index"
|
WEBSITE_ITEM_INDEX = "website_items_index"
|
||||||
WEBSITE_ITEM_KEY_PREFIX = "website_item:"
|
WEBSITE_ITEM_KEY_PREFIX = "website_item:"
|
||||||
@ -35,12 +37,9 @@ def is_redisearch_enabled():
|
|||||||
def is_search_module_loaded():
|
def is_search_module_loaded():
|
||||||
try:
|
try:
|
||||||
cache = frappe.cache()
|
cache = frappe.cache()
|
||||||
out = cache.execute_command("MODULE LIST")
|
for module in cache.module_list():
|
||||||
|
if module.get(b"name") == b"search":
|
||||||
parsed_output = " ".join(
|
return True
|
||||||
(" ".join([frappe.as_unicode(s) for s in o if not isinstance(s, int)]) for o in out)
|
|
||||||
)
|
|
||||||
return "search" in parsed_output
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return False # handling older redis versions
|
return False # handling older redis versions
|
||||||
|
|
||||||
@ -58,18 +57,18 @@ def if_redisearch_enabled(function):
|
|||||||
|
|
||||||
|
|
||||||
def make_key(key):
|
def make_key(key):
|
||||||
return "{0}|{1}".format(frappe.conf.db_name, key).encode("utf-8")
|
return frappe.cache().make_key(key)
|
||||||
|
|
||||||
|
|
||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
def create_website_items_index():
|
def create_website_items_index():
|
||||||
"Creates Index Definition."
|
"Creates Index Definition."
|
||||||
|
|
||||||
# CREATE index
|
redis = frappe.cache()
|
||||||
client = Client(make_key(WEBSITE_ITEM_INDEX), conn=frappe.cache())
|
index = redis.ft(WEBSITE_ITEM_INDEX)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client.drop_index() # drop if already exists
|
index.dropindex() # drop if already exists
|
||||||
except ResponseError:
|
except ResponseError:
|
||||||
# will most likely raise a ResponseError if index does not exist
|
# will most likely raise a ResponseError if index does not exist
|
||||||
# ignore and create index
|
# ignore and create index
|
||||||
@ -86,9 +85,10 @@ def create_website_items_index():
|
|||||||
if "web_item_name" in idx_fields:
|
if "web_item_name" in idx_fields:
|
||||||
idx_fields.remove("web_item_name")
|
idx_fields.remove("web_item_name")
|
||||||
|
|
||||||
idx_fields = list(map(to_search_field, idx_fields))
|
idx_fields = [to_search_field(f) for f in idx_fields]
|
||||||
|
|
||||||
client.create_index(
|
# TODO: sortable?
|
||||||
|
index.create_index(
|
||||||
[TextField("web_item_name", sortable=True)] + idx_fields,
|
[TextField("web_item_name", sortable=True)] + idx_fields,
|
||||||
definition=idx_def,
|
definition=idx_def,
|
||||||
)
|
)
|
||||||
@ -119,8 +119,8 @@ def insert_item_to_index(website_item_doc):
|
|||||||
|
|
||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
def insert_to_name_ac(web_name, doc_name):
|
def insert_to_name_ac(web_name, doc_name):
|
||||||
ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=frappe.cache())
|
ac = frappe.cache().ft()
|
||||||
ac.add_suggestions(Suggestion(web_name, payload=doc_name))
|
ac.sugadd(WEBSITE_ITEM_NAME_AUTOCOMPLETE, Suggestion(web_name, payload=doc_name))
|
||||||
|
|
||||||
|
|
||||||
def create_web_item_map(website_item_doc):
|
def create_web_item_map(website_item_doc):
|
||||||
@ -157,9 +157,8 @@ def delete_item_from_index(website_item_doc):
|
|||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
def delete_from_ac_dict(website_item_doc):
|
def delete_from_ac_dict(website_item_doc):
|
||||||
"""Removes this items's name from autocomplete dictionary"""
|
"""Removes this items's name from autocomplete dictionary"""
|
||||||
cache = frappe.cache()
|
ac = frappe.cache().ft()
|
||||||
name_ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=cache)
|
ac.sugdel(website_item_doc.web_item_name)
|
||||||
name_ac.delete(website_item_doc.web_item_name)
|
|
||||||
|
|
||||||
|
|
||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
@ -170,8 +169,6 @@ def define_autocomplete_dictionary():
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
cache = frappe.cache()
|
cache = frappe.cache()
|
||||||
item_ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=cache)
|
|
||||||
item_group_ac = AutoCompleter(make_key(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE), conn=cache)
|
|
||||||
|
|
||||||
# Delete both autocomplete dicts
|
# Delete both autocomplete dicts
|
||||||
try:
|
try:
|
||||||
@ -180,38 +177,43 @@ def define_autocomplete_dictionary():
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise_redisearch_error()
|
raise_redisearch_error()
|
||||||
|
|
||||||
create_items_autocomplete_dict(autocompleter=item_ac)
|
create_items_autocomplete_dict()
|
||||||
create_item_groups_autocomplete_dict(autocompleter=item_group_ac)
|
create_item_groups_autocomplete_dict()
|
||||||
|
|
||||||
|
|
||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
def create_items_autocomplete_dict(autocompleter):
|
def create_items_autocomplete_dict():
|
||||||
"Add items as suggestions in Autocompleter."
|
"Add items as suggestions in Autocompleter."
|
||||||
|
|
||||||
|
ac = frappe.cache().ft()
|
||||||
items = frappe.get_all(
|
items = frappe.get_all(
|
||||||
"Website Item", fields=["web_item_name", "item_group"], filters={"published": 1}
|
"Website Item", fields=["web_item_name", "item_group"], filters={"published": 1}
|
||||||
)
|
)
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
autocompleter.add_suggestions(Suggestion(item.web_item_name))
|
ac.sugadd(WEBSITE_ITEM_NAME_AUTOCOMPLETE, Suggestion(item.web_item_name))
|
||||||
|
|
||||||
|
|
||||||
@if_redisearch_enabled
|
@if_redisearch_enabled
|
||||||
def create_item_groups_autocomplete_dict(autocompleter):
|
def create_item_groups_autocomplete_dict():
|
||||||
"Add item groups with weightage as suggestions in Autocompleter."
|
"Add item groups with weightage as suggestions in Autocompleter."
|
||||||
|
|
||||||
published_item_groups = frappe.get_all(
|
published_item_groups = frappe.get_all(
|
||||||
"Item Group", fields=["name", "route", "weightage"], filters={"show_in_website": 1}
|
"Item Group", fields=["name", "route", "weightage"], filters={"show_in_website": 1}
|
||||||
)
|
)
|
||||||
if not published_item_groups:
|
if not published_item_groups:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
ac = frappe.cache().ft()
|
||||||
|
|
||||||
for item_group in published_item_groups:
|
for item_group in published_item_groups:
|
||||||
payload = json.dumps({"name": item_group.name, "route": item_group.route})
|
payload = json.dumps({"name": item_group.name, "route": item_group.route})
|
||||||
autocompleter.add_suggestions(
|
ac.sugadd(
|
||||||
|
WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE,
|
||||||
Suggestion(
|
Suggestion(
|
||||||
string=item_group.name,
|
string=item_group.name,
|
||||||
score=frappe.utils.flt(item_group.weightage) or 1.0,
|
score=frappe.utils.flt(item_group.weightage) or 1.0,
|
||||||
payload=payload, # additional info that can be retrieved later
|
payload=payload, # additional info that can be retrieved later
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ def handle_incoming_call(**kwargs):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
frappe.db.rollback()
|
frappe.db.rollback()
|
||||||
exotel_settings.log_error("Error in Exotel incoming call")
|
exotel_settings.log_error("Error in Exotel incoming call")
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
@ -236,7 +236,7 @@ def get_term_loans(date, term_loan=None, loan_type=None):
|
|||||||
AND l.is_term_loan =1
|
AND l.is_term_loan =1
|
||||||
AND rs.payment_date <= %s
|
AND rs.payment_date <= %s
|
||||||
AND rs.is_accrued=0 {0}
|
AND rs.is_accrued=0 {0}
|
||||||
AND rs.interest_amount > 0
|
AND rs.principal_amount > 0
|
||||||
AND l.status = 'Disbursed'
|
AND l.status = 'Disbursed'
|
||||||
ORDER BY rs.payment_date""".format(
|
ORDER BY rs.payment_date""".format(
|
||||||
condition
|
condition
|
||||||
|
@ -735,6 +735,7 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
)
|
)
|
||||||
amounts["pending_accrual_entries"] = pending_accrual_entries
|
amounts["pending_accrual_entries"] = pending_accrual_entries
|
||||||
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
|
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
|
||||||
|
amounts["written_off_amount"] = flt(against_loan_doc.written_off_amount, precision)
|
||||||
|
|
||||||
if final_due_date:
|
if final_due_date:
|
||||||
amounts["due_date"] = final_due_date
|
amounts["due_date"] = final_due_date
|
||||||
|
@ -57,7 +57,7 @@ def process_loan_interest_accrual_for_demand_loans(
|
|||||||
|
|
||||||
def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=None, loan=None):
|
def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=None, loan=None):
|
||||||
|
|
||||||
if not term_loan_accrual_pending(posting_date or nowdate()):
|
if not term_loan_accrual_pending(posting_date or nowdate(), loan=loan):
|
||||||
return
|
return
|
||||||
|
|
||||||
loan_process = frappe.new_doc("Process Loan Interest Accrual")
|
loan_process = frappe.new_doc("Process Loan Interest Accrual")
|
||||||
@ -71,9 +71,12 @@ def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=No
|
|||||||
return loan_process.name
|
return loan_process.name
|
||||||
|
|
||||||
|
|
||||||
def term_loan_accrual_pending(date):
|
def term_loan_accrual_pending(date, loan=None):
|
||||||
pending_accrual = frappe.db.get_value(
|
filters = {"payment_date": ("<=", date), "is_accrued": 0}
|
||||||
"Repayment Schedule", {"payment_date": ("<=", date), "is_accrued": 0}
|
|
||||||
)
|
if loan:
|
||||||
|
filters.update({"parent": loan})
|
||||||
|
|
||||||
|
pending_accrual = frappe.db.get_value("Repayment Schedule", filters)
|
||||||
|
|
||||||
return pending_accrual
|
return pending_accrual
|
||||||
|
@ -415,7 +415,7 @@ def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=No
|
|||||||
},
|
},
|
||||||
"Maintenance Schedule Item": {
|
"Maintenance Schedule Item": {
|
||||||
"doctype": "Maintenance Visit Purpose",
|
"doctype": "Maintenance Visit Purpose",
|
||||||
"condition": lambda doc: doc.item_name == item_name,
|
"condition": lambda doc: doc.item_name == item_name if item_name else True,
|
||||||
"field_map": {"sales_person": "service_person"},
|
"field_map": {"sales_person": "service_person"},
|
||||||
"postprocess": update_serial,
|
"postprocess": update_serial,
|
||||||
},
|
},
|
||||||
|
@ -656,6 +656,8 @@ class ProductionPlan(Document):
|
|||||||
row.idx = idx + 1
|
row.idx = idx + 1
|
||||||
self.append("sub_assembly_items", row)
|
self.append("sub_assembly_items", row)
|
||||||
|
|
||||||
|
self.set_default_supplier_for_subcontracting_order()
|
||||||
|
|
||||||
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
|
def set_sub_assembly_items_based_on_level(self, row, bom_data, manufacturing_type=None):
|
||||||
"Modify bom_data, set additional details."
|
"Modify bom_data, set additional details."
|
||||||
for data in bom_data:
|
for data in bom_data:
|
||||||
@ -667,6 +669,32 @@ class ProductionPlan(Document):
|
|||||||
"Subcontract" if data.is_sub_contracted_item else "In House"
|
"Subcontract" if data.is_sub_contracted_item else "In House"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_default_supplier_for_subcontracting_order(self):
|
||||||
|
items = [
|
||||||
|
d.production_item for d in self.sub_assembly_items if d.type_of_manufacturing == "Subcontract"
|
||||||
|
]
|
||||||
|
|
||||||
|
if not items:
|
||||||
|
return
|
||||||
|
|
||||||
|
default_supplier = frappe._dict(
|
||||||
|
frappe.get_all(
|
||||||
|
"Item Default",
|
||||||
|
fields=["parent", "default_supplier"],
|
||||||
|
filters={"parent": ("in", items), "default_supplier": ("is", "set")},
|
||||||
|
as_list=1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not default_supplier:
|
||||||
|
return
|
||||||
|
|
||||||
|
for row in self.sub_assembly_items:
|
||||||
|
if row.type_of_manufacturing != "Subcontract":
|
||||||
|
continue
|
||||||
|
|
||||||
|
row.supplier = default_supplier.get(row.production_item)
|
||||||
|
|
||||||
def combine_subassembly_items(self, sub_assembly_items_store):
|
def combine_subassembly_items(self, sub_assembly_items_store):
|
||||||
"Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No."
|
"Aggregate if same: Item, Warehouse, Inhouse/Outhouse Manu.g, BOM No."
|
||||||
key_wise_data = {}
|
key_wise_data = {}
|
||||||
|
@ -281,6 +281,31 @@ class TestProductionPlan(FrappeTestCase):
|
|||||||
pln.reload()
|
pln.reload()
|
||||||
pln.cancel()
|
pln.cancel()
|
||||||
|
|
||||||
|
def test_production_plan_subassembly_default_supplier(self):
|
||||||
|
from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom
|
||||||
|
|
||||||
|
bom_tree_1 = {"Test Laptop": {"Test Motherboard": {"Test Motherboard Wires": {}}}}
|
||||||
|
bom = create_nested_bom(bom_tree_1, prefix="")
|
||||||
|
|
||||||
|
item_doc = frappe.get_doc("Item", "Test Motherboard")
|
||||||
|
company = "_Test Company"
|
||||||
|
|
||||||
|
item_doc.is_sub_contracted_item = 1
|
||||||
|
for row in item_doc.item_defaults:
|
||||||
|
if row.company == company and not row.default_supplier:
|
||||||
|
row.default_supplier = "_Test Supplier"
|
||||||
|
|
||||||
|
if not item_doc.item_defaults:
|
||||||
|
item_doc.append("item_defaults", {"company": company, "default_supplier": "_Test Supplier"})
|
||||||
|
|
||||||
|
item_doc.save()
|
||||||
|
|
||||||
|
plan = create_production_plan(item_code="Test Laptop", use_multi_level_bom=1, do_not_submit=True)
|
||||||
|
plan.get_sub_assembly_items()
|
||||||
|
plan.set_default_supplier_for_subcontracting_order()
|
||||||
|
|
||||||
|
self.assertEqual(plan.sub_assembly_items[0].supplier, "_Test Supplier")
|
||||||
|
|
||||||
def test_production_plan_combine_subassembly(self):
|
def test_production_plan_combine_subassembly(self):
|
||||||
"""
|
"""
|
||||||
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
|
Test combining Sub assembly items belonging to the same BOM in Prod Plan.
|
||||||
|
@ -26,6 +26,8 @@ from erpnext.stock.doctype.stock_entry import test_stock_entry
|
|||||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
from erpnext.stock.utils import get_bin
|
from erpnext.stock.utils import get_bin
|
||||||
|
|
||||||
|
test_dependencies = ["BOM"]
|
||||||
|
|
||||||
|
|
||||||
class TestWorkOrder(FrappeTestCase):
|
class TestWorkOrder(FrappeTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -7,6 +7,6 @@ def get_data():
|
|||||||
"non_standard_fieldnames": {"Batch": "reference_name"},
|
"non_standard_fieldnames": {"Batch": "reference_name"},
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{"label": _("Transactions"), "items": ["Stock Entry", "Job Card", "Pick List"]},
|
{"label": _("Transactions"), "items": ["Stock Entry", "Job Card", "Pick List"]},
|
||||||
{"label": _("Reference"), "items": ["Serial No", "Batch"]},
|
{"label": _("Reference"), "items": ["Serial No", "Batch", "Material Request"]},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -313,3 +313,4 @@ erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
|
|||||||
erpnext.patches.v14_0.fix_crm_no_of_employees
|
erpnext.patches.v14_0.fix_crm_no_of_employees
|
||||||
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
||||||
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
||||||
|
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
||||||
|
@ -14,7 +14,8 @@ def execute():
|
|||||||
|
|
||||||
for sla in frappe.get_all("Service Level Agreement"):
|
for sla in frappe.get_all("Service Level Agreement"):
|
||||||
agreement = frappe.get_doc("Service Level Agreement", sla.name)
|
agreement = frappe.get_doc("Service Level Agreement", sla.name)
|
||||||
agreement.document_type = "Issue"
|
agreement.db_set("document_type", "Issue")
|
||||||
|
agreement.reload()
|
||||||
agreement.apply_sla_for_resolution = 1
|
agreement.apply_sla_for_resolution = 1
|
||||||
agreement.append("sla_fulfilled_on", {"status": "Resolved"})
|
agreement.append("sla_fulfilled_on", {"status": "Resolved"})
|
||||||
agreement.append("sla_fulfilled_on", {"status": "Closed"})
|
agreement.append("sla_fulfilled_on", {"status": "Closed"})
|
||||||
|
@ -16,18 +16,18 @@ def execute():
|
|||||||
delete_auto_email_reports(report)
|
delete_auto_email_reports(report)
|
||||||
check_and_delete_linked_reports(report)
|
check_and_delete_linked_reports(report)
|
||||||
|
|
||||||
frappe.delete_doc("Report", report)
|
frappe.delete_doc("Report", report, force=True)
|
||||||
|
|
||||||
|
|
||||||
def delete_auto_email_reports(report):
|
def delete_auto_email_reports(report):
|
||||||
"""Check for one or multiple Auto Email Reports and delete"""
|
"""Check for one or multiple Auto Email Reports and delete"""
|
||||||
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
|
auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
|
||||||
for auto_email_report in auto_email_reports:
|
for auto_email_report in auto_email_reports:
|
||||||
frappe.delete_doc("Auto Email Report", auto_email_report[0])
|
frappe.delete_doc("Auto Email Report", auto_email_report[0], force=True)
|
||||||
|
|
||||||
|
|
||||||
def delete_links_from_desktop_icons(report):
|
def delete_links_from_desktop_icons(report):
|
||||||
"""Check for one or multiple Desktop Icons and delete"""
|
"""Check for one or multiple Desktop Icons and delete"""
|
||||||
desktop_icons = frappe.db.get_values("Desktop Icon", {"_report": report}, ["name"])
|
desktop_icons = frappe.db.get_values("Desktop Icon", {"_report": report}, ["name"])
|
||||||
for desktop_icon in desktop_icons:
|
for desktop_icon in desktop_icons:
|
||||||
frappe.delete_doc("Desktop Icon", desktop_icon[0])
|
frappe.delete_doc("Desktop Icon", desktop_icon[0], force=True)
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe import qb
|
||||||
|
from frappe.utils import create_batch
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"):
|
||||||
|
|
||||||
|
gle = qb.DocType("GL Entry")
|
||||||
|
ple = qb.DocType("Payment Ledger Entry")
|
||||||
|
|
||||||
|
# get ple and their remarks from GL Entry
|
||||||
|
pl_entries = (
|
||||||
|
qb.from_(ple)
|
||||||
|
.left_join(gle)
|
||||||
|
.on(
|
||||||
|
(ple.account == gle.account)
|
||||||
|
& (ple.party_type == gle.party_type)
|
||||||
|
& (ple.party == gle.party)
|
||||||
|
& (ple.voucher_type == gle.voucher_type)
|
||||||
|
& (ple.voucher_no == gle.voucher_no)
|
||||||
|
& (ple.company == gle.company)
|
||||||
|
)
|
||||||
|
.select(
|
||||||
|
ple.company,
|
||||||
|
ple.account,
|
||||||
|
ple.party_type,
|
||||||
|
ple.party,
|
||||||
|
ple.voucher_type,
|
||||||
|
ple.voucher_no,
|
||||||
|
gle.remarks.as_("gle_remarks"),
|
||||||
|
)
|
||||||
|
.where((ple.delinked == 0) & (gle.is_cancelled == 0))
|
||||||
|
.run(as_dict=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
if pl_entries:
|
||||||
|
# split into multiple batches, update and commit for each batch
|
||||||
|
batch_size = 1000
|
||||||
|
for batch in create_batch(pl_entries, batch_size):
|
||||||
|
for entry in batch:
|
||||||
|
query = (
|
||||||
|
qb.update(ple)
|
||||||
|
.set(ple.remarks, entry.gle_remarks)
|
||||||
|
.where(
|
||||||
|
(ple.company == entry.company)
|
||||||
|
& (ple.account == entry.account)
|
||||||
|
& (ple.party_type == entry.party_type)
|
||||||
|
& (ple.party == entry.party)
|
||||||
|
& (ple.voucher_type == entry.voucher_type)
|
||||||
|
& (ple.voucher_no == entry.voucher_no)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
query.run()
|
||||||
|
|
||||||
|
frappe.db.commit()
|
@ -1,3 +1,4 @@
|
|||||||
|
import click
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
|
|
||||||
@ -16,6 +17,19 @@ def execute():
|
|||||||
for opportunity in opportunities:
|
for opportunity in opportunities:
|
||||||
company_currency = erpnext.get_company_currency(opportunity.company)
|
company_currency = erpnext.get_company_currency(opportunity.company)
|
||||||
|
|
||||||
|
if opportunity.currency is None or opportunity.currency == "":
|
||||||
|
opportunity.currency = company_currency
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Opportunity",
|
||||||
|
opportunity.name,
|
||||||
|
{"currency": opportunity.currency},
|
||||||
|
update_modified=False,
|
||||||
|
)
|
||||||
|
click.secho(
|
||||||
|
f' Opportunity `{opportunity.name}` has no currency set. Setting it to company currency as default: `{opportunity.currency}`"\n',
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
# base total and total will be 0 only since item table did not have amount field earlier
|
# base total and total will be 0 only since item table did not have amount field earlier
|
||||||
if opportunity.currency != company_currency:
|
if opportunity.currency != company_currency:
|
||||||
conversion_rate = get_exchange_rate(opportunity.currency, company_currency)
|
conversion_rate = get_exchange_rate(opportunity.currency, company_currency)
|
||||||
|
@ -1,127 +1,70 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "Prompt",
|
"autoname": "Prompt",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2019-04-19 15:04:05.317138",
|
"creation": "2019-04-19 15:04:05.317138",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 0,
|
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"weight",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "weight",
|
"fieldname": "weight",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
"label": "Weight"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Weight",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "description",
|
"fieldname": "description",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"hidden": 0,
|
"label": "Description"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Description",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"links": [],
|
||||||
"hide_toolbar": 0,
|
"modified": "2022-08-29 17:46:41.342979",
|
||||||
"idx": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-04-19 15:31:48.080164",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Projects",
|
"module": "Projects",
|
||||||
"name": "Task Type",
|
"name": "Task Type",
|
||||||
"name_case": "",
|
"naming_rule": "Set by user",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Projects Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Projects User",
|
||||||
|
"share": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
"track_changes": 1,
|
"states": [],
|
||||||
"track_seen": 0,
|
"track_changes": 1
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -39,6 +39,12 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
this._calculate_taxes_and_totals();
|
this._calculate_taxes_and_totals();
|
||||||
this.calculate_discount_amount();
|
this.calculate_discount_amount();
|
||||||
|
|
||||||
|
// # Update grand total as per cash and non trade discount
|
||||||
|
if (this.frm.doc.apply_discount_on == "Grand Total" && this.frm.doc.is_cash_or_non_trade_discount) {
|
||||||
|
this.frm.doc.grand_total -= this.frm.doc.discount_amount;
|
||||||
|
this.frm.doc.base_grand_total -= this.frm.doc.base_discount_amount;
|
||||||
|
}
|
||||||
|
|
||||||
await this.calculate_shipping_charges();
|
await this.calculate_shipping_charges();
|
||||||
|
|
||||||
// Advance calculation applicable to Sales /Purchase Invoice
|
// Advance calculation applicable to Sales /Purchase Invoice
|
||||||
@ -633,6 +639,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
this.frm.doc.base_discount_amount = flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate,
|
this.frm.doc.base_discount_amount = flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate,
|
||||||
precision("base_discount_amount"));
|
precision("base_discount_amount"));
|
||||||
|
|
||||||
|
if (this.frm.doc.apply_discount_on == "Grand Total" && this.frm.doc.is_cash_or_non_trade_discount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var total_for_discount_amount = this.get_total_for_discount_amount();
|
var total_for_discount_amount = this.get_total_for_discount_amount();
|
||||||
var net_total = 0;
|
var net_total = 0;
|
||||||
// calculate item amount after Discount Amount
|
// calculate item amount after Discount Amount
|
||||||
|
@ -84,7 +84,7 @@ def create_qr_code(doc, method=None):
|
|||||||
tlv_array.append("".join([tag, length, value]))
|
tlv_array.append("".join([tag, length, value]))
|
||||||
|
|
||||||
# Invoice Amount
|
# Invoice Amount
|
||||||
invoice_amount = str(doc.grand_total)
|
invoice_amount = str(doc.base_grand_total)
|
||||||
tag = bytes([4]).hex()
|
tag = bytes([4]).hex()
|
||||||
length = bytes([len(invoice_amount)]).hex()
|
length = bytes([len(invoice_amount)]).hex()
|
||||||
value = invoice_amount.encode("utf-8").hex()
|
value = invoice_amount.encode("utf-8").hex()
|
||||||
@ -144,7 +144,7 @@ def get_vat_amount(doc):
|
|||||||
|
|
||||||
for tax in doc.get("taxes"):
|
for tax in doc.get("taxes"):
|
||||||
if tax.account_head in vat_accounts:
|
if tax.account_head in vat_accounts:
|
||||||
vat_amount += tax.tax_amount
|
vat_amount += tax.base_tax_amount
|
||||||
|
|
||||||
return vat_amount
|
return vat_amount
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
|||||||
|
|
||||||
def set_expired_status():
|
def set_expired_status():
|
||||||
# filter out submitted non expired quotations whose validity has been ended
|
# filter out submitted non expired quotations whose validity has been ended
|
||||||
cond = "`tabQuotation`.docstatus = 1 and `tabQuotation`.status != 'Expired' and `tabQuotation`.valid_till < %s"
|
cond = "`tabQuotation`.docstatus = 1 and `tabQuotation`.status NOT IN ('Expired', 'Lost') and `tabQuotation`.valid_till < %s"
|
||||||
# check if those QUO have SO against it
|
# check if those QUO have SO against it
|
||||||
so_against_quo = """
|
so_against_quo = """
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -59,7 +59,36 @@ frappe.ui.form.on("Sales Order", {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frm.doc.docstatus === 0 && frm.doc.is_internal_customer) {
|
||||||
|
frm.events.get_items_from_internal_purchase_order(frm);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get_items_from_internal_purchase_order(frm) {
|
||||||
|
frm.add_custom_button(__('Purchase Order'), () => {
|
||||||
|
erpnext.utils.map_current_doc({
|
||||||
|
method: 'erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order',
|
||||||
|
source_doctype: 'Purchase Order',
|
||||||
|
target: frm,
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
label: 'Supplier',
|
||||||
|
fieldname: 'supplier',
|
||||||
|
fieldtype: 'Link',
|
||||||
|
options: 'Supplier'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
get_query_filters: {
|
||||||
|
company: frm.doc.company,
|
||||||
|
is_internal_supplier: 1,
|
||||||
|
docstatus: 1,
|
||||||
|
status: ['!=', 'Completed']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, __('Get Items From'));
|
||||||
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
if (!frm.doc.transaction_date){
|
if (!frm.doc.transaction_date){
|
||||||
frm.set_value('transaction_date', frappe.datetime.get_today())
|
frm.set_value('transaction_date', frappe.datetime.get_today())
|
||||||
|
@ -892,6 +892,7 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t
|
|||||||
target.additional_discount_percentage = 0.0
|
target.additional_discount_percentage = 0.0
|
||||||
target.discount_amount = 0.0
|
target.discount_amount = 0.0
|
||||||
target.inter_company_order_reference = ""
|
target.inter_company_order_reference = ""
|
||||||
|
target.shipping_rule = ""
|
||||||
|
|
||||||
default_price_list = frappe.get_value("Supplier", supplier, "default_price_list")
|
default_price_list = frappe.get_value("Supplier", supplier, "default_price_list")
|
||||||
if default_price_list:
|
if default_price_list:
|
||||||
@ -1010,6 +1011,7 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None):
|
|||||||
target.additional_discount_percentage = 0.0
|
target.additional_discount_percentage = 0.0
|
||||||
target.discount_amount = 0.0
|
target.discount_amount = 0.0
|
||||||
target.inter_company_order_reference = ""
|
target.inter_company_order_reference = ""
|
||||||
|
target.shipping_rule = ""
|
||||||
target.customer = ""
|
target.customer = ""
|
||||||
target.customer_name = ""
|
target.customer_name = ""
|
||||||
target.run_method("set_missing_values")
|
target.run_method("set_missing_values")
|
||||||
|
@ -92,7 +92,11 @@
|
|||||||
"section_break_63",
|
"section_break_63",
|
||||||
"page_break",
|
"page_break",
|
||||||
"item_tax_rate",
|
"item_tax_rate",
|
||||||
"transaction_date"
|
"transaction_date",
|
||||||
|
"inter_transfer_reference_section",
|
||||||
|
"purchase_order",
|
||||||
|
"column_break_89",
|
||||||
|
"purchase_order_item"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -809,12 +813,36 @@
|
|||||||
"label": "Picked Qty (in Stock UOM)",
|
"label": "Picked Qty (in Stock UOM)",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "inter_transfer_reference_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Inter Transfer Reference"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Order",
|
||||||
|
"options": "Purchase Order",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_89",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order_item",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Purchase Order Item",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-17 05:27:41.603006",
|
"modified": "2022-09-06 13:24:18.065312",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Order Item",
|
"name": "Sales Order Item",
|
||||||
|
@ -168,7 +168,7 @@ class Analytics(object):
|
|||||||
def get_sales_transactions_based_on_items(self):
|
def get_sales_transactions_based_on_items(self):
|
||||||
|
|
||||||
if self.filters["value_quantity"] == "Value":
|
if self.filters["value_quantity"] == "Value":
|
||||||
value_field = "base_amount"
|
value_field = "base_net_amount"
|
||||||
else:
|
else:
|
||||||
value_field = "stock_qty"
|
value_field = "stock_qty"
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ class Analytics(object):
|
|||||||
|
|
||||||
def get_sales_transactions_based_on_item_group(self):
|
def get_sales_transactions_based_on_item_group(self):
|
||||||
if self.filters["value_quantity"] == "Value":
|
if self.filters["value_quantity"] == "Value":
|
||||||
value_field = "base_amount"
|
value_field = "base_net_amount"
|
||||||
else:
|
else:
|
||||||
value_field = "qty"
|
value_field = "qty"
|
||||||
|
|
||||||
|
@ -85,7 +85,6 @@
|
|||||||
"depreciation_expense_account",
|
"depreciation_expense_account",
|
||||||
"series_for_depreciation_entry",
|
"series_for_depreciation_entry",
|
||||||
"expenses_included_in_asset_valuation",
|
"expenses_included_in_asset_valuation",
|
||||||
"repair_and_maintenance_account",
|
|
||||||
"column_break_40",
|
"column_break_40",
|
||||||
"disposal_account",
|
"disposal_account",
|
||||||
"depreciation_cost_center",
|
"depreciation_cost_center",
|
||||||
@ -234,7 +233,6 @@
|
|||||||
"label": "Default Warehouse for Sales Return",
|
"label": "Default Warehouse for Sales Return",
|
||||||
"options": "Warehouse"
|
"options": "Warehouse"
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "country",
|
"fieldname": "country",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -678,12 +676,6 @@
|
|||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Fixed Asset Defaults"
|
"label": "Fixed Asset Defaults"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "repair_and_maintenance_account",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"label": "Repair and Maintenance Account",
|
|
||||||
"options": "Account"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_28",
|
"fieldname": "section_break_28",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@ -709,7 +701,7 @@
|
|||||||
"image_field": "company_logo",
|
"image_field": "company_logo",
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-30 18:03:18.701314",
|
"modified": "2022-08-16 16:09:02.327724",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Company",
|
"name": "Company",
|
||||||
|
@ -10,79 +10,89 @@
|
|||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
|
"basic_details_tab",
|
||||||
"basic_information",
|
"basic_information",
|
||||||
"employee",
|
"employee",
|
||||||
"naming_series",
|
"naming_series",
|
||||||
"first_name",
|
"first_name",
|
||||||
"middle_name",
|
"middle_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
"salutation",
|
|
||||||
"employee_name",
|
"employee_name",
|
||||||
"image",
|
"column_break_9",
|
||||||
"column_break1",
|
|
||||||
"company",
|
|
||||||
"status",
|
|
||||||
"gender",
|
"gender",
|
||||||
"date_of_birth",
|
"date_of_birth",
|
||||||
|
"salutation",
|
||||||
|
"column_break1",
|
||||||
"date_of_joining",
|
"date_of_joining",
|
||||||
"employee_number",
|
"image",
|
||||||
"emergency_contact_details",
|
"status",
|
||||||
"person_to_be_contacted",
|
|
||||||
"relation",
|
|
||||||
"column_break_19",
|
|
||||||
"emergency_phone_number",
|
|
||||||
"erpnext_user",
|
"erpnext_user",
|
||||||
"user_id",
|
"user_id",
|
||||||
"create_user",
|
"create_user",
|
||||||
"create_user_permission",
|
"create_user_permission",
|
||||||
"employment_details",
|
"company_details_section",
|
||||||
"scheduled_confirmation_date",
|
"company",
|
||||||
"final_confirmation_date",
|
|
||||||
"col_break_22",
|
|
||||||
"contract_end_date",
|
|
||||||
"notice_number_of_days",
|
|
||||||
"date_of_retirement",
|
|
||||||
"job_profile",
|
|
||||||
"department",
|
"department",
|
||||||
|
"employee_number",
|
||||||
|
"column_break_25",
|
||||||
"designation",
|
"designation",
|
||||||
"reports_to",
|
"reports_to",
|
||||||
"column_break_31",
|
"column_break_18",
|
||||||
"branch",
|
"branch",
|
||||||
|
"employment_details",
|
||||||
|
"scheduled_confirmation_date",
|
||||||
|
"column_break_32",
|
||||||
|
"final_confirmation_date",
|
||||||
|
"contract_end_date",
|
||||||
|
"col_break_22",
|
||||||
|
"notice_number_of_days",
|
||||||
|
"date_of_retirement",
|
||||||
|
"contact_details",
|
||||||
|
"cell_number",
|
||||||
|
"column_break_40",
|
||||||
|
"personal_email",
|
||||||
|
"company_email",
|
||||||
|
"column_break4",
|
||||||
|
"prefered_contact_email",
|
||||||
|
"prefered_email",
|
||||||
|
"unsubscribed",
|
||||||
|
"address_section",
|
||||||
|
"current_address",
|
||||||
|
"current_accommodation_type",
|
||||||
|
"column_break_46",
|
||||||
|
"permanent_address",
|
||||||
|
"permanent_accommodation_type",
|
||||||
|
"emergency_contact_details",
|
||||||
|
"person_to_be_contacted",
|
||||||
|
"column_break_55",
|
||||||
|
"emergency_phone_number",
|
||||||
|
"column_break_19",
|
||||||
|
"relation",
|
||||||
"attendance_and_leave_details",
|
"attendance_and_leave_details",
|
||||||
"attendance_device_id",
|
"attendance_device_id",
|
||||||
"column_break_44",
|
"column_break_44",
|
||||||
"holiday_list",
|
"holiday_list",
|
||||||
"salary_information",
|
"salary_information",
|
||||||
"salary_currency",
|
|
||||||
"ctc",
|
"ctc",
|
||||||
"payroll_cost_center",
|
"salary_currency",
|
||||||
"column_break_52",
|
"salary_mode",
|
||||||
|
"bank_details_section",
|
||||||
"bank_name",
|
"bank_name",
|
||||||
"bank_ac_no",
|
"bank_ac_no",
|
||||||
"contact_details",
|
|
||||||
"cell_number",
|
|
||||||
"prefered_email",
|
|
||||||
"personal_email",
|
|
||||||
"unsubscribed",
|
|
||||||
"permanent_accommodation_type",
|
|
||||||
"permanent_address",
|
|
||||||
"column_break4",
|
|
||||||
"prefered_contact_email",
|
|
||||||
"company_email",
|
|
||||||
"current_accommodation_type",
|
|
||||||
"current_address",
|
|
||||||
"sb53",
|
|
||||||
"bio",
|
|
||||||
"personal_details",
|
"personal_details",
|
||||||
"passport_number",
|
|
||||||
"date_of_issue",
|
|
||||||
"valid_upto",
|
|
||||||
"place_of_issue",
|
|
||||||
"marital_status",
|
"marital_status",
|
||||||
"blood_group",
|
|
||||||
"column_break6",
|
|
||||||
"family_background",
|
"family_background",
|
||||||
|
"column_break6",
|
||||||
|
"blood_group",
|
||||||
"health_details",
|
"health_details",
|
||||||
|
"passport_details_section",
|
||||||
|
"passport_number",
|
||||||
|
"valid_upto",
|
||||||
|
"column_break_73",
|
||||||
|
"date_of_issue",
|
||||||
|
"place_of_issue",
|
||||||
|
"profile_tab",
|
||||||
|
"bio",
|
||||||
"educational_qualification",
|
"educational_qualification",
|
||||||
"education",
|
"education",
|
||||||
"previous_work_experience",
|
"previous_work_experience",
|
||||||
@ -92,16 +102,20 @@
|
|||||||
"exit",
|
"exit",
|
||||||
"resignation_letter_date",
|
"resignation_letter_date",
|
||||||
"relieving_date",
|
"relieving_date",
|
||||||
"reason_for_leaving",
|
|
||||||
"leave_encashed",
|
|
||||||
"encashment_date",
|
|
||||||
"exit_interview_details",
|
"exit_interview_details",
|
||||||
"held_on",
|
"held_on",
|
||||||
"new_workplace",
|
"new_workplace",
|
||||||
|
"column_break_99",
|
||||||
|
"leave_encashed",
|
||||||
|
"encashment_date",
|
||||||
|
"feedback_section",
|
||||||
|
"reason_for_leaving",
|
||||||
|
"column_break_104",
|
||||||
"feedback",
|
"feedback",
|
||||||
"lft",
|
"lft",
|
||||||
"rgt",
|
"rgt",
|
||||||
"old_parent"
|
"old_parent",
|
||||||
|
"connections_tab"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -261,7 +275,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "erpnext_user",
|
"fieldname": "erpnext_user",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "ERPNext User"
|
"label": "User Details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "System User (login) ID. If set, it will become default for all HR forms.",
|
"description": "System User (login) ID. If set, it will become default for all HR forms.",
|
||||||
@ -289,8 +303,8 @@
|
|||||||
"allow_in_quick_entry": 1,
|
"allow_in_quick_entry": 1,
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "employment_details",
|
"fieldname": "employment_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Joining Details"
|
"label": "Joining"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "scheduled_confirmation_date",
|
"fieldname": "scheduled_confirmation_date",
|
||||||
@ -331,12 +345,6 @@
|
|||||||
"oldfieldname": "date_of_retirement",
|
"oldfieldname": "date_of_retirement",
|
||||||
"oldfieldtype": "Date"
|
"oldfieldtype": "Date"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"collapsible": 1,
|
|
||||||
"fieldname": "job_profile",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Department"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -366,10 +374,6 @@
|
|||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Employee"
|
"options": "Employee"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_31",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "branch",
|
"fieldname": "branch",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -391,7 +395,7 @@
|
|||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "salary_information",
|
"fieldname": "salary_information",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Salary Details",
|
"label": "Salary Details",
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"width": "50%"
|
"width": "50%"
|
||||||
@ -423,8 +427,8 @@
|
|||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "contact_details",
|
"fieldname": "contact_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Contact Details"
|
"label": "Contact"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "cell_number",
|
"fieldname": "cell_number",
|
||||||
@ -493,12 +497,6 @@
|
|||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Current Address"
|
"label": "Current Address"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"collapsible": 1,
|
|
||||||
"fieldname": "sb53",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Personal Bio"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "Short biography for website and other publications.",
|
"description": "Short biography for website and other publications.",
|
||||||
"fieldname": "bio",
|
"fieldname": "bio",
|
||||||
@ -508,7 +506,7 @@
|
|||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "personal_details",
|
"fieldname": "personal_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Personal Details"
|
"label": "Personal Details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -601,7 +599,7 @@
|
|||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "exit",
|
"fieldname": "exit",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Exit",
|
"label": "Exit",
|
||||||
"oldfieldtype": "Section Break"
|
"oldfieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
@ -702,7 +700,7 @@
|
|||||||
{
|
{
|
||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "attendance_and_leave_details",
|
"fieldname": "attendance_and_leave_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Tab Break",
|
||||||
"label": "Attendance and Leave Details"
|
"label": "Attendance and Leave Details"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -713,10 +711,6 @@
|
|||||||
"fieldname": "column_break_19",
|
"fieldname": "column_break_19",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "column_break_52",
|
|
||||||
"fieldtype": "Column Break"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "salary_currency",
|
"fieldname": "salary_currency",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
@ -728,13 +722,95 @@
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Cost to Company (CTC)",
|
"label": "Cost to Company (CTC)",
|
||||||
"options": "salary_currency"
|
"options": "salary_currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "basic_details_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Basic Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "company_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Company Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_18",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"fieldname": "address_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_46",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "profile_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Profile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "passport_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Passport Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_73",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "bank_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Bank Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_9",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_25",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "connections_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Connections",
|
||||||
|
"show_dashboard": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_32",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_40",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_55",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_99",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "feedback_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Feedback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_104",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 24,
|
"idx": 24,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-27 01:29:32.952091",
|
"modified": "2022-08-23 13:47:46.944993",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
|
@ -178,6 +178,7 @@ class DeliveryNote(SellingController):
|
|||||||
if (
|
if (
|
||||||
cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate"))
|
cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate"))
|
||||||
and not self.is_return
|
and not self.is_return
|
||||||
|
and not self.is_internal_customer
|
||||||
):
|
):
|
||||||
self.validate_rate_with_reference_doc(
|
self.validate_rate_with_reference_doc(
|
||||||
[
|
[
|
||||||
@ -896,6 +897,8 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
|||||||
"name": "delivery_note_item",
|
"name": "delivery_note_item",
|
||||||
"batch_no": "batch_no",
|
"batch_no": "batch_no",
|
||||||
"serial_no": "serial_no",
|
"serial_no": "serial_no",
|
||||||
|
"purchase_order": "purchase_order",
|
||||||
|
"purchase_order_item": "purchase_order_item",
|
||||||
},
|
},
|
||||||
"field_no_map": ["warehouse"],
|
"field_no_map": ["warehouse"],
|
||||||
},
|
},
|
||||||
|
@ -86,6 +86,10 @@
|
|||||||
"expense_account",
|
"expense_account",
|
||||||
"allow_zero_valuation_rate",
|
"allow_zero_valuation_rate",
|
||||||
"column_break_71",
|
"column_break_71",
|
||||||
|
"internal_transfer_section",
|
||||||
|
"purchase_order",
|
||||||
|
"column_break_82",
|
||||||
|
"purchase_order_item",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
"dimension_col_break",
|
"dimension_col_break",
|
||||||
@ -777,13 +781,39 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapsible": 1,
|
||||||
|
"depends_on": "eval:parent.is_internal_customer == 1",
|
||||||
|
"fieldname": "internal_transfer_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Internal Transfer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Purchase Order",
|
||||||
|
"options": "Purchase Order",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_82",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "purchase_order_item",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Purchase Order Item",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-17 05:25:47.711177",
|
"modified": "2022-09-06 14:19:42.876357",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note Item",
|
"name": "Delivery Note Item",
|
||||||
|
@ -30,6 +30,7 @@ frappe.ui.form.on('Inventory Dimension', {
|
|||||||
|
|
||||||
onload(frm) {
|
onload(frm) {
|
||||||
frm.trigger('render_traget_field');
|
frm.trigger('render_traget_field');
|
||||||
|
frm.trigger("set_parent_fields");
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh(frm) {
|
refresh(frm) {
|
||||||
@ -52,6 +53,30 @@ frappe.ui.form.on('Inventory Dimension', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
document_type(frm) {
|
||||||
|
frm.trigger("set_parent_fields");
|
||||||
|
},
|
||||||
|
|
||||||
|
set_parent_fields(frm) {
|
||||||
|
if (frm.doc.apply_to_all_doctypes) {
|
||||||
|
frm.set_df_property("fetch_from_parent", "options", frm.doc.reference_document);
|
||||||
|
} else if (frm.doc.document_type && frm.doc.istable) {
|
||||||
|
frappe.call({
|
||||||
|
method: 'erpnext.stock.doctype.inventory_dimension.inventory_dimension.get_parent_fields',
|
||||||
|
args: {
|
||||||
|
child_doctype: frm.doc.document_type,
|
||||||
|
dimension_name: frm.doc.reference_document
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
if (r.message && r.message.length) {
|
||||||
|
frm.set_df_property("fetch_from_parent", "options",
|
||||||
|
[""].concat(r.message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
delete_dimension(frm) {
|
delete_dimension(frm) {
|
||||||
let msg = (`
|
let msg = (`
|
||||||
Custom fields related to this dimension will be deleted on deletion of dimension.
|
Custom fields related to this dimension will be deleted on deletion of dimension.
|
||||||
|
@ -144,16 +144,15 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "istable",
|
|
||||||
"description": "Set fieldname or DocType name like Supplier, Customer etc.",
|
"description": "Set fieldname or DocType name like Supplier, Customer etc.",
|
||||||
"fieldname": "fetch_from_parent",
|
"fieldname": "fetch_from_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Select",
|
||||||
"label": "Fetch Value From Parent Form"
|
"label": "Fetch Value From Parent Form"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-08-17 11:43:24.722441",
|
"modified": "2022-09-02 13:29:04.098469",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Inventory Dimension",
|
"name": "Inventory Dimension",
|
||||||
|
@ -236,3 +236,30 @@ def get_inventory_dimensions():
|
|||||||
def delete_dimension(dimension):
|
def delete_dimension(dimension):
|
||||||
doc = frappe.get_doc("Inventory Dimension", dimension)
|
doc = frappe.get_doc("Inventory Dimension", dimension)
|
||||||
doc.delete()
|
doc.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_parent_fields(child_doctype, dimension_name):
|
||||||
|
parent_doctypes = frappe.get_all(
|
||||||
|
"DocField", fields=["parent"], filters={"options": child_doctype}
|
||||||
|
)
|
||||||
|
|
||||||
|
fields = []
|
||||||
|
|
||||||
|
fields.extend(
|
||||||
|
frappe.get_all(
|
||||||
|
"DocField",
|
||||||
|
fields=["fieldname as value", "label"],
|
||||||
|
filters={"options": dimension_name, "parent": ("in", [d.parent for d in parent_doctypes])},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fields.extend(
|
||||||
|
frappe.get_all(
|
||||||
|
"Custom Field",
|
||||||
|
fields=["fieldname as value", "label"],
|
||||||
|
filters={"options": dimension_name, "dt": ("in", [d.parent for d in parent_doctypes])},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return fields
|
||||||
|
@ -2,14 +2,17 @@
|
|||||||
# See license.txt
|
# See license.txt
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||||
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import (
|
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import (
|
||||||
CanNotBeChildDoc,
|
CanNotBeChildDoc,
|
||||||
CanNotBeDefaultDimension,
|
CanNotBeDefaultDimension,
|
||||||
DoNotChangeError,
|
DoNotChangeError,
|
||||||
delete_dimension,
|
delete_dimension,
|
||||||
)
|
)
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
|
||||||
@ -136,6 +139,58 @@ class TestInventoryDimension(FrappeTestCase):
|
|||||||
self.assertTrue(inv_dim1.has_stock_ledger())
|
self.assertTrue(inv_dim1.has_stock_ledger())
|
||||||
self.assertRaises(DoNotChangeError, inv_dim1.save)
|
self.assertRaises(DoNotChangeError, inv_dim1.save)
|
||||||
|
|
||||||
|
def test_inventory_dimension_for_purchase_receipt_and_delivery_note(self):
|
||||||
|
create_inventory_dimension(
|
||||||
|
reference_document="Rack",
|
||||||
|
type_of_transaction="Both",
|
||||||
|
dimension_name="Rack",
|
||||||
|
apply_to_all_doctypes=1,
|
||||||
|
fetch_from_parent="Rack",
|
||||||
|
)
|
||||||
|
|
||||||
|
create_custom_field(
|
||||||
|
"Purchase Receipt", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack")
|
||||||
|
)
|
||||||
|
|
||||||
|
create_custom_field(
|
||||||
|
"Delivery Note", dict(fieldname="rack", label="Rack", fieldtype="Link", options="Rack")
|
||||||
|
)
|
||||||
|
|
||||||
|
frappe.reload_doc("stock", "doctype", "purchase_receipt_item")
|
||||||
|
frappe.reload_doc("stock", "doctype", "delivery_note_item")
|
||||||
|
|
||||||
|
pr_doc = make_purchase_receipt(qty=2, do_not_submit=True)
|
||||||
|
pr_doc.rack = "Rack 1"
|
||||||
|
pr_doc.save()
|
||||||
|
pr_doc.submit()
|
||||||
|
|
||||||
|
pr_doc.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(pr_doc.items[0].rack, "Rack 1")
|
||||||
|
sle_rack = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_detail_no": pr_doc.items[0].name, "voucher_type": pr_doc.doctype},
|
||||||
|
"rack",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(sle_rack, "Rack 1")
|
||||||
|
|
||||||
|
dn_doc = create_delivery_note(qty=2, do_not_submit=True)
|
||||||
|
dn_doc.rack = "Rack 1"
|
||||||
|
dn_doc.save()
|
||||||
|
dn_doc.submit()
|
||||||
|
|
||||||
|
dn_doc.load_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(dn_doc.items[0].rack, "Rack 1")
|
||||||
|
sle_rack = frappe.db.get_value(
|
||||||
|
"Stock Ledger Entry",
|
||||||
|
{"voucher_detail_no": dn_doc.items[0].name, "voucher_type": dn_doc.doctype},
|
||||||
|
"rack",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(sle_rack, "Rack 1")
|
||||||
|
|
||||||
|
|
||||||
def prepare_test_data():
|
def prepare_test_data():
|
||||||
if not frappe.db.exists("DocType", "Shelf"):
|
if not frappe.db.exists("DocType", "Shelf"):
|
||||||
@ -160,6 +215,28 @@ def prepare_test_data():
|
|||||||
|
|
||||||
create_warehouse("Shelf Warehouse")
|
create_warehouse("Shelf Warehouse")
|
||||||
|
|
||||||
|
if not frappe.db.exists("DocType", "Rack"):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "DocType",
|
||||||
|
"name": "Rack",
|
||||||
|
"module": "Stock",
|
||||||
|
"custom": 1,
|
||||||
|
"naming_rule": "By fieldname",
|
||||||
|
"autoname": "field:rack_name",
|
||||||
|
"fields": [{"label": "Rack Name", "fieldname": "rack_name", "fieldtype": "Data"}],
|
||||||
|
"permissions": [
|
||||||
|
{"role": "System Manager", "permlevel": 0, "read": 1, "write": 1, "create": 1, "delete": 1}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
for rack in ["Rack 1"]:
|
||||||
|
if not frappe.db.exists("Rack", rack):
|
||||||
|
frappe.get_doc({"doctype": "Rack", "rack_name": rack}).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
create_warehouse("Rack Warehouse")
|
||||||
|
|
||||||
|
|
||||||
def create_inventory_dimension(**args):
|
def create_inventory_dimension(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
@ -562,7 +562,7 @@ $.extend(erpnext.item, {
|
|||||||
let selected_attributes = {};
|
let selected_attributes = {};
|
||||||
me.multiple_variant_dialog.$wrapper.find('.form-column').each((i, col) => {
|
me.multiple_variant_dialog.$wrapper.find('.form-column').each((i, col) => {
|
||||||
if(i===0) return;
|
if(i===0) return;
|
||||||
let attribute_name = $(col).find('label').html().trim();
|
let attribute_name = $(col).find('.control-label').html().trim();
|
||||||
selected_attributes[attribute_name] = [];
|
selected_attributes[attribute_name] = [];
|
||||||
let checked_opts = $(col).find('.checkbox input');
|
let checked_opts = $(col).find('.checkbox input');
|
||||||
checked_opts.each((i, opt) => {
|
checked_opts.each((i, opt) => {
|
||||||
|
@ -5,7 +5,7 @@ def get_data():
|
|||||||
return {
|
return {
|
||||||
"heatmap": True,
|
"heatmap": True,
|
||||||
"heatmap_message": _("This is based on stock movement. See {0} for details").format(
|
"heatmap_message": _("This is based on stock movement. See {0} for details").format(
|
||||||
'<a href="#query-report/Stock Ledger">' + _("Stock Ledger") + "</a>"
|
'<a href="/app/query-report/Stock Ledger">' + _("Stock Ledger") + "</a>"
|
||||||
),
|
),
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"non_standard_fieldnames": {
|
"non_standard_fieldnames": {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Barcode",
|
"label": "Barcode",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
|
"reqd": 1,
|
||||||
"unique": 1
|
"unique": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -36,7 +37,7 @@
|
|||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-06-01 06:24:33.969534",
|
"modified": "2022-08-24 19:59:47.871677",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Barcode",
|
"name": "Item Barcode",
|
||||||
|
@ -48,41 +48,31 @@
|
|||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "Item",
|
"options": "Item",
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1,
|
"search_index": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "uom",
|
"fieldname": "uom",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "UOM",
|
"label": "UOM",
|
||||||
"options": "UOM",
|
"options": "UOM"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"description": "Quantity that must be bought or sold per UOM",
|
"description": "Quantity that must be bought or sold per UOM",
|
||||||
"fieldname": "packing_unit",
|
"fieldname": "packing_unit",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Packing Unit",
|
"label": "Packing Unit"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_17",
|
"fieldname": "column_break_17",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "item_name",
|
"fieldname": "item_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Item Name",
|
"label": "Item Name",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "item_code.brand",
|
"fetch_from": "item_code.brand",
|
||||||
@ -90,36 +80,29 @@
|
|||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Brand",
|
"label": "Brand",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "item_description",
|
"fieldname": "item_description",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"label": "Item Description",
|
"label": "Item Description",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "price_list_details",
|
"fieldname": "price_list_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Price List",
|
"label": "Price List",
|
||||||
"options": "fa fa-tags",
|
"options": "fa fa-tags"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "price_list",
|
"fieldname": "price_list",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Price List",
|
"label": "Price List",
|
||||||
"options": "Price List",
|
"options": "Price List",
|
||||||
"reqd": 1,
|
"reqd": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
@ -127,49 +110,37 @@
|
|||||||
"fieldname": "customer",
|
"fieldname": "customer",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Customer",
|
"label": "Customer",
|
||||||
"options": "Customer",
|
"options": "Customer"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:doc.buying == 1",
|
"depends_on": "eval:doc.buying == 1",
|
||||||
"fieldname": "supplier",
|
"fieldname": "supplier",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Supplier",
|
"label": "Supplier",
|
||||||
"options": "Supplier",
|
"options": "Supplier"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "buying",
|
"fieldname": "buying",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Buying",
|
"label": "Buying",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "selling",
|
"fieldname": "selling",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Selling",
|
"label": "Selling",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "item_details",
|
"fieldname": "item_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"options": "fa fa-tag",
|
"options": "fa fa-tag"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"bold": 1,
|
"bold": 1,
|
||||||
@ -177,15 +148,11 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Currency",
|
"label": "Currency",
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "col_br_1",
|
"fieldname": "col_br_1",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "price_list_rate",
|
"fieldname": "price_list_rate",
|
||||||
@ -197,80 +164,61 @@
|
|||||||
"oldfieldname": "ref_rate",
|
"oldfieldname": "ref_rate",
|
||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"options": "currency",
|
"options": "currency",
|
||||||
"reqd": 1,
|
"reqd": 1
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_15",
|
"fieldname": "section_break_15",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "Today",
|
"default": "Today",
|
||||||
"fieldname": "valid_from",
|
"fieldname": "valid_from",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Valid From",
|
"label": "Valid From"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
"fieldname": "lead_time_days",
|
"fieldname": "lead_time_days",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Lead Time in days",
|
"label": "Lead Time in days"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_18",
|
"fieldname": "column_break_18",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "valid_upto",
|
"fieldname": "valid_upto",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"label": "Valid Upto",
|
"label": "Valid Upto"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_24",
|
"fieldname": "section_break_24",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "note",
|
"fieldname": "note",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"label": "Note",
|
"label": "Note"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "reference",
|
"fieldname": "reference",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Reference",
|
"in_standard_filter": 1,
|
||||||
"show_days": 1,
|
"label": "Reference"
|
||||||
"show_seconds": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "batch_no",
|
"fieldname": "batch_no",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Batch No",
|
"label": "Batch No",
|
||||||
"options": "Batch",
|
"options": "Batch"
|
||||||
"show_days": 1,
|
|
||||||
"show_seconds": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-flag",
|
"icon": "fa fa-flag",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-12-08 18:12:15.395772",
|
"modified": "2022-09-02 16:33:55.612992",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Price",
|
"name": "Item Price",
|
||||||
@ -307,6 +255,7 @@
|
|||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "ASC",
|
"sort_order": "ASC",
|
||||||
|
"states": [],
|
||||||
"title_field": "item_name",
|
"title_field": "item_name",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
3
erpnext/stock/doctype/item_price/item_price_list.js
Normal file
3
erpnext/stock/doctype/item_price/item_price_list.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
frappe.listview_settings['Item Price'] = {
|
||||||
|
hide_name_column: true,
|
||||||
|
};
|
@ -1,95 +1,43 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_import": 0,
|
|
||||||
"allow_rename": 0,
|
|
||||||
"beta": 0,
|
|
||||||
"creation": "2013-02-22 01:28:01",
|
"creation": "2013-02-22 01:28:01",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"supplier",
|
||||||
|
"supplier_part_no"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "supplier",
|
"fieldname": "supplier",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supplier",
|
"label": "Supplier",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Supplier",
|
"options": "Supplier",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "supplier_part_no",
|
"fieldname": "supplier_part_no",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supplier Part Number",
|
"label": "Supplier Part Number",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"print_width": "200px",
|
"print_width": "200px",
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"unique": 0,
|
|
||||||
"width": "200px"
|
"width": "200px"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"links": [],
|
||||||
"modified": "2017-02-20 13:29:32.569715",
|
"modified": "2022-09-07 12:33:55.780062",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Item Supplier",
|
"name": "Item Supplier",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 0,
|
"sort_field": "modified",
|
||||||
"read_only": 0,
|
"sort_order": "DESC",
|
||||||
"read_only_onload": 0,
|
"states": [],
|
||||||
"show_name_in_global_search": 0,
|
"track_changes": 1
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
@ -37,7 +37,8 @@
|
|||||||
"tc_name",
|
"tc_name",
|
||||||
"terms",
|
"terms",
|
||||||
"reference",
|
"reference",
|
||||||
"job_card"
|
"job_card",
|
||||||
|
"work_order"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -309,16 +310,24 @@
|
|||||||
"label": "Transfer Status",
|
"label": "Transfer Status",
|
||||||
"options": "\nNot Started\nIn Transit\nCompleted",
|
"options": "\nNot Started\nIn Transit\nCompleted",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "work_order",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Work Order",
|
||||||
|
"options": "Work Order",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-ticket",
|
"icon": "fa fa-ticket",
|
||||||
"idx": 70,
|
"idx": 70,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-08-17 20:16:12.737743",
|
"modified": "2022-08-25 11:49:28.155048",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Material Request",
|
"name": "Material Request",
|
||||||
|
"naming_rule": "By \"Naming Series\" field",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@ -386,5 +395,6 @@
|
|||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
"title_field": "title"
|
"title_field": "title"
|
||||||
}
|
}
|
@ -24,7 +24,8 @@ frappe.ui.form.on('Repost Item Valuation', {
|
|||||||
frm.set_query("voucher_no", () => {
|
frm.set_query("voucher_no", () => {
|
||||||
return {
|
return {
|
||||||
filters: {
|
filters: {
|
||||||
company: frm.doc.company
|
company: frm.doc.company,
|
||||||
|
docstatus: 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -174,6 +174,8 @@ frappe.ui.form.on('Stock Entry', {
|
|||||||
if(!items.length) {
|
if(!items.length) {
|
||||||
items = frm.doc.items;
|
items = frm.doc.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mr.work_order = frm.doc.work_order;
|
||||||
items.forEach(function(item) {
|
items.forEach(function(item) {
|
||||||
var mr_item = frappe.model.add_child(mr, 'items');
|
var mr_item = frappe.model.add_child(mr, 'items');
|
||||||
mr_item.item_code = item.item_code;
|
mr_item.item_code = item.item_code;
|
||||||
|
@ -116,6 +116,7 @@ class StockEntry(StockController):
|
|||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
self.validate_work_order()
|
self.validate_work_order()
|
||||||
self.validate_bom()
|
self.validate_bom()
|
||||||
|
self.validate_purchase_order()
|
||||||
|
|
||||||
if self.purpose in ("Manufacture", "Repack"):
|
if self.purpose in ("Manufacture", "Repack"):
|
||||||
self.mark_finished_and_scrap_items()
|
self.mark_finished_and_scrap_items()
|
||||||
@ -946,6 +947,19 @@ class StockEntry(StockController):
|
|||||||
item_code = d.original_item or d.item_code
|
item_code = d.original_item or d.item_code
|
||||||
validate_bom_no(item_code, d.bom_no)
|
validate_bom_no(item_code, d.bom_no)
|
||||||
|
|
||||||
|
def validate_purchase_order(self):
|
||||||
|
if self.purpose == "Send to Subcontractor" and self.get("purchase_order"):
|
||||||
|
is_old_subcontracting_flow = frappe.db.get_value(
|
||||||
|
"Purchase Order", self.purchase_order, "is_old_subcontracting_flow"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not is_old_subcontracting_flow:
|
||||||
|
frappe.throw(
|
||||||
|
_("Please select Subcontracting Order instead of Purchase Order {0}").format(
|
||||||
|
self.purchase_order
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def mark_finished_and_scrap_items(self):
|
def mark_finished_and_scrap_items(self):
|
||||||
if any([d.item_code for d in self.items if (d.is_finished_item and d.t_warehouse)]):
|
if any([d.item_code for d in self.items if (d.is_finished_item and d.t_warehouse)]):
|
||||||
return
|
return
|
||||||
@ -2215,7 +2229,7 @@ class StockEntry(StockController):
|
|||||||
return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
|
return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
|
||||||
|
|
||||||
def update_subcontracting_order_status(self):
|
def update_subcontracting_order_status(self):
|
||||||
if self.subcontracting_order and self.purpose == "Send to Subcontractor":
|
if self.subcontracting_order and self.purpose in ["Send to Subcontractor", "Material Transfer"]:
|
||||||
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
|
||||||
update_subcontracting_order_status,
|
update_subcontracting_order_status,
|
||||||
)
|
)
|
||||||
@ -2554,27 +2568,26 @@ def get_supplied_items(
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_items_from_subcontracting_order(source_name, target_doc=None):
|
def get_items_from_subcontracting_order(source_name, target_doc=None):
|
||||||
sco = frappe.get_doc("Subcontracting Order", source_name)
|
def post_process(source, target):
|
||||||
|
target.stock_entry_type = target.purpose = "Send to Subcontractor"
|
||||||
|
target.subcontracting_order = source_name
|
||||||
|
|
||||||
if sco.docstatus == 1:
|
if target.items:
|
||||||
if target_doc and isinstance(target_doc, str):
|
target.items = []
|
||||||
target_doc = frappe.get_doc(json.loads(target_doc))
|
|
||||||
|
|
||||||
if target_doc.items:
|
|
||||||
target_doc.items = []
|
|
||||||
|
|
||||||
warehouses = {}
|
warehouses = {}
|
||||||
for item in sco.items:
|
for item in source.items:
|
||||||
warehouses[item.name] = item.warehouse
|
warehouses[item.name] = item.warehouse
|
||||||
|
|
||||||
for item in sco.supplied_items:
|
for item in source.supplied_items:
|
||||||
target_doc.append(
|
target.append(
|
||||||
"items",
|
"items",
|
||||||
{
|
{
|
||||||
"s_warehouse": warehouses.get(item.reference_name),
|
"s_warehouse": warehouses.get(item.reference_name),
|
||||||
"t_warehouse": sco.supplier_warehouse,
|
"t_warehouse": source.supplier_warehouse,
|
||||||
|
"subcontracted_item": item.main_item_code,
|
||||||
"item_code": item.rm_item_code,
|
"item_code": item.rm_item_code,
|
||||||
"qty": item.required_qty,
|
"qty": max(item.required_qty - item.total_supplied_qty, 0),
|
||||||
"transfer_qty": item.required_qty,
|
"transfer_qty": item.required_qty,
|
||||||
"uom": item.stock_uom,
|
"uom": item.stock_uom,
|
||||||
"stock_uom": item.stock_uom,
|
"stock_uom": item.stock_uom,
|
||||||
@ -2582,6 +2595,23 @@ def get_items_from_subcontracting_order(source_name, target_doc=None):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_doc = get_mapped_doc(
|
||||||
|
"Subcontracting Order",
|
||||||
|
source_name,
|
||||||
|
{
|
||||||
|
"Subcontracting Order": {
|
||||||
|
"doctype": "Stock Entry",
|
||||||
|
"field_no_map": ["purchase_order"],
|
||||||
|
"validation": {
|
||||||
|
"docstatus": ["=", 1],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target_doc,
|
||||||
|
post_process,
|
||||||
|
ignore_child_tables=True,
|
||||||
|
)
|
||||||
|
|
||||||
return target_doc
|
return target_doc
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,9 +107,9 @@ frappe.ui.form.on('Subcontracting Order', {
|
|||||||
get_materials_from_supplier: function (frm) {
|
get_materials_from_supplier: function (frm) {
|
||||||
let sco_rm_details = [];
|
let sco_rm_details = [];
|
||||||
|
|
||||||
if (frm.doc.supplied_items && (frm.doc.per_received == 100)) {
|
if (frm.doc.supplied_items && frm.doc.per_received > 0) {
|
||||||
frm.doc.supplied_items.forEach(d => {
|
frm.doc.supplied_items.forEach(d => {
|
||||||
if (d.total_supplied_qty && d.total_supplied_qty != d.consumed_qty) {
|
if (d.total_supplied_qty > 0 && d.total_supplied_qty != d.consumed_qty) {
|
||||||
sco_rm_details.push(d.name);
|
sco_rm_details.push(d.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -160,14 +160,11 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
|||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
if (doc.docstatus == 1) {
|
if (doc.docstatus == 1) {
|
||||||
if (doc.status != 'Completed') {
|
if (!['Closed', 'Completed'].includes(doc.status)) {
|
||||||
if (flt(doc.per_received) < 100) {
|
if (flt(doc.per_received) < 100) {
|
||||||
cur_frm.add_custom_button(__('Subcontracting Receipt'), this.make_subcontracting_receipt, __('Create'));
|
cur_frm.add_custom_button(__('Subcontracting Receipt'), this.make_subcontracting_receipt, __('Create'));
|
||||||
if (me.has_unsupplied_items()) {
|
if (me.has_unsupplied_items()) {
|
||||||
cur_frm.add_custom_button(__('Material to Supplier'),
|
cur_frm.add_custom_button(__('Material to Supplier'), this.make_stock_entry, __('Transfer'));
|
||||||
() => {
|
|
||||||
me.make_stock_entry();
|
|
||||||
}, __('Transfer'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
|
||||||
@ -195,120 +192,6 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
|||||||
transaction_controller.autofill_warehouse(child_table, warehouse_field, warehouse);
|
transaction_controller.autofill_warehouse(child_table, warehouse_field, warehouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
make_stock_entry() {
|
|
||||||
var items = $.map(cur_frm.doc.items, (d) => d.bom ? d.item_code : false);
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
if (items.length >= 1) {
|
|
||||||
me.raw_material_data = [];
|
|
||||||
me.show_dialog = 1;
|
|
||||||
let title = __('Transfer Material to Supplier');
|
|
||||||
let fields = [
|
|
||||||
{ fieldtype: 'Section Break', label: __('Raw Materials') },
|
|
||||||
{
|
|
||||||
fieldname: 'sub_con_rm_items', fieldtype: 'Table', label: __('Items'),
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
fieldtype: 'Data',
|
|
||||||
fieldname: 'item_code',
|
|
||||||
label: __('Item'),
|
|
||||||
read_only: 1,
|
|
||||||
in_list_view: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Data',
|
|
||||||
fieldname: 'rm_item_code',
|
|
||||||
label: __('Raw Material'),
|
|
||||||
read_only: 1,
|
|
||||||
in_list_view: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Float',
|
|
||||||
read_only: 1,
|
|
||||||
fieldname: 'qty',
|
|
||||||
label: __('Quantity'),
|
|
||||||
in_list_view: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Data',
|
|
||||||
read_only: 1,
|
|
||||||
fieldname: 'warehouse',
|
|
||||||
label: __('Reserve Warehouse'),
|
|
||||||
in_list_view: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Float',
|
|
||||||
read_only: 1,
|
|
||||||
fieldname: 'rate',
|
|
||||||
label: __('Rate'),
|
|
||||||
hidden: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Float',
|
|
||||||
read_only: 1,
|
|
||||||
fieldname: 'amount',
|
|
||||||
label: __('Amount'),
|
|
||||||
hidden: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fieldtype: 'Link',
|
|
||||||
read_only: 1,
|
|
||||||
fieldname: 'uom',
|
|
||||||
label: __('UOM'),
|
|
||||||
hidden: 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
data: me.raw_material_data,
|
|
||||||
get_data: () => me.raw_material_data
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
me.dialog = new frappe.ui.Dialog({
|
|
||||||
title: title, fields: fields
|
|
||||||
});
|
|
||||||
|
|
||||||
if (me.frm.doc['supplied_items']) {
|
|
||||||
me.frm.doc['supplied_items'].forEach((item) => {
|
|
||||||
if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) {
|
|
||||||
me.raw_material_data.push({
|
|
||||||
'name': item.name,
|
|
||||||
'item_code': item.main_item_code,
|
|
||||||
'rm_item_code': item.rm_item_code,
|
|
||||||
'item_name': item.rm_item_code,
|
|
||||||
'qty': item.required_qty - item.supplied_qty,
|
|
||||||
'warehouse': item.reserve_warehouse,
|
|
||||||
'rate': item.rate,
|
|
||||||
'amount': item.amount,
|
|
||||||
'stock_uom': item.stock_uom
|
|
||||||
});
|
|
||||||
me.dialog.fields_dict.sub_con_rm_items.grid.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
me.dialog.get_field('sub_con_rm_items').check_all_rows();
|
|
||||||
|
|
||||||
me.dialog.show();
|
|
||||||
this.dialog.set_primary_action(__('Transfer'), () => {
|
|
||||||
me.values = me.dialog.get_values();
|
|
||||||
if (me.values) {
|
|
||||||
me.values.sub_con_rm_items.map((row, i) => {
|
|
||||||
if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) {
|
|
||||||
let row_id = i + 1;
|
|
||||||
frappe.throw(__('Item Code, warehouse and quantity are required on row {0}', [row_id]));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
me.make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children());
|
|
||||||
me.dialog.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
me.dialog.get_close_btn().on('click', () => {
|
|
||||||
me.dialog.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
has_unsupplied_items() {
|
has_unsupplied_items() {
|
||||||
return this.frm.doc['supplied_items'].some(item => item.required_qty > item.supplied_qty);
|
return this.frm.doc['supplied_items'].some(item => item.required_qty > item.supplied_qty);
|
||||||
}
|
}
|
||||||
@ -321,6 +204,15 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_stock_entry() {
|
||||||
|
frappe.model.open_mapped_doc({
|
||||||
|
method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontracting_order',
|
||||||
|
source_name: cur_frm.doc.name,
|
||||||
|
freeze: true,
|
||||||
|
freeze_message: __('Creating Stock Entry ...')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
make_rm_stock_entry(rm_items) {
|
make_rm_stock_entry(rm_items) {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: 'erpnext.controllers.subcontracting_controller.make_rm_stock_entry',
|
method: 'erpnext.controllers.subcontracting_controller.make_rm_stock_entry',
|
||||||
|
@ -153,7 +153,7 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
else:
|
else:
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
|
|
||||||
def update_status(self, status=None, update_modified=False):
|
def update_status(self, status=None, update_modified=True):
|
||||||
if self.docstatus >= 1 and not status:
|
if self.docstatus >= 1 and not status:
|
||||||
if self.docstatus == 1:
|
if self.docstatus == 1:
|
||||||
if self.status == "Draft":
|
if self.status == "Draft":
|
||||||
@ -162,6 +162,10 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
status = "Completed"
|
status = "Completed"
|
||||||
elif self.per_received > 0 and self.per_received < 100:
|
elif self.per_received > 0 and self.per_received < 100:
|
||||||
status = "Partially Received"
|
status = "Partially Received"
|
||||||
|
for item in self.supplied_items:
|
||||||
|
if item.returned_qty:
|
||||||
|
status = "Closed"
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
total_required_qty = total_supplied_qty = 0
|
total_required_qty = total_supplied_qty = 0
|
||||||
for item in self.supplied_items:
|
for item in self.supplied_items:
|
||||||
@ -176,7 +180,10 @@ class SubcontractingOrder(SubcontractingController):
|
|||||||
elif self.docstatus == 2:
|
elif self.docstatus == 2:
|
||||||
status = "Cancelled"
|
status = "Cancelled"
|
||||||
|
|
||||||
frappe.db.set_value("Subcontracting Order", self.name, "status", status, update_modified)
|
if status:
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Subcontracting Order", self.name, "status", status, update_modified=update_modified
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
@ -10,6 +10,7 @@ frappe.listview_settings['Subcontracting Order'] = {
|
|||||||
"Completed": "green",
|
"Completed": "green",
|
||||||
"Partial Material Transferred": "purple",
|
"Partial Material Transferred": "purple",
|
||||||
"Material Transferred": "blue",
|
"Material Transferred": "blue",
|
||||||
|
"Closed": "red",
|
||||||
};
|
};
|
||||||
return [__(doc.status), status_colors[doc.status], "status,=," + doc.status];
|
return [__(doc.status), status_colors[doc.status], "status,=," + doc.status];
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,10 @@ import frappe
|
|||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_subcontracting_order
|
from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_subcontracting_order
|
||||||
from erpnext.controllers.subcontracting_controller import make_rm_stock_entry
|
from erpnext.controllers.subcontracting_controller import (
|
||||||
|
get_materials_from_supplier,
|
||||||
|
make_rm_stock_entry,
|
||||||
|
)
|
||||||
from erpnext.controllers.tests.test_subcontracting_controller import (
|
from erpnext.controllers.tests.test_subcontracting_controller import (
|
||||||
get_rm_items,
|
get_rm_items,
|
||||||
get_subcontracting_order,
|
get_subcontracting_order,
|
||||||
@ -89,6 +92,16 @@ class TestSubcontractingOrder(FrappeTestCase):
|
|||||||
sco.load_from_db()
|
sco.load_from_db()
|
||||||
self.assertEqual(sco.status, "Partially Received")
|
self.assertEqual(sco.status, "Partially Received")
|
||||||
|
|
||||||
|
# Closed
|
||||||
|
ste = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items])
|
||||||
|
ste.save()
|
||||||
|
ste.submit()
|
||||||
|
sco.load_from_db()
|
||||||
|
self.assertEqual(sco.status, "Closed")
|
||||||
|
ste.cancel()
|
||||||
|
sco.load_from_db()
|
||||||
|
self.assertEqual(sco.status, "Partially Received")
|
||||||
|
|
||||||
# Completed
|
# Completed
|
||||||
scr = make_subcontracting_receipt(sco.name)
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
scr.save()
|
scr.save()
|
||||||
@ -174,22 +187,13 @@ class TestSubcontractingOrder(FrappeTestCase):
|
|||||||
self.assertEqual(len(ste.items), len(rm_items))
|
self.assertEqual(len(ste.items), len(rm_items))
|
||||||
|
|
||||||
def test_update_reserved_qty_for_subcontracting(self):
|
def test_update_reserved_qty_for_subcontracting(self):
|
||||||
# Make stock available for raw materials
|
# Create RM Material Receipt
|
||||||
make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
|
make_stock_entry(target="_Test Warehouse - _TC", item_code="_Test Item", qty=10, basic_rate=100)
|
||||||
make_stock_entry(
|
make_stock_entry(
|
||||||
target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100
|
target="_Test Warehouse - _TC", item_code="_Test Item Home Desktop 100", qty=20, basic_rate=100
|
||||||
)
|
)
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse 1 - _TC", item_code="_Test Item", qty=30, basic_rate=100
|
|
||||||
)
|
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse 1 - _TC",
|
|
||||||
item_code="_Test Item Home Desktop 100",
|
|
||||||
qty=30,
|
|
||||||
basic_rate=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
bin1 = frappe.db.get_value(
|
bin_before_sco = frappe.db.get_value(
|
||||||
"Bin",
|
"Bin",
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
|
fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
|
||||||
@ -209,102 +213,97 @@ class TestSubcontractingOrder(FrappeTestCase):
|
|||||||
]
|
]
|
||||||
sco = get_subcontracting_order(service_items=service_items)
|
sco = get_subcontracting_order(service_items=service_items)
|
||||||
|
|
||||||
bin2 = frappe.db.get_value(
|
bin_after_sco = frappe.db.get_value(
|
||||||
"Bin",
|
"Bin",
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
|
fieldname=["reserved_qty_for_sub_contract", "projected_qty", "modified"],
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(bin2.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
# reserved_qty_for_sub_contract should be increased by 10
|
||||||
self.assertEqual(bin2.projected_qty, bin1.projected_qty - 10)
|
self.assertEqual(
|
||||||
self.assertNotEqual(bin1.modified, bin2.modified)
|
bin_after_sco.reserved_qty_for_sub_contract, bin_before_sco.reserved_qty_for_sub_contract + 10
|
||||||
|
)
|
||||||
|
|
||||||
# Create stock transfer
|
# projected_qty should be decreased by 10
|
||||||
|
self.assertEqual(bin_after_sco.projected_qty, bin_before_sco.projected_qty - 10)
|
||||||
|
|
||||||
|
self.assertNotEqual(bin_before_sco.modified, bin_after_sco.modified)
|
||||||
|
|
||||||
|
# Create Stock Entry(Send to Subcontractor)
|
||||||
rm_items = [
|
rm_items = [
|
||||||
{
|
{
|
||||||
"item_code": "_Test FG Item",
|
"item_code": "_Test FG Item",
|
||||||
"rm_item_code": "_Test Item",
|
"rm_item_code": "_Test Item",
|
||||||
"item_name": "_Test Item",
|
"item_name": "_Test Item",
|
||||||
"qty": 6,
|
"qty": 10,
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"rate": 100,
|
"rate": 100,
|
||||||
"amount": 600,
|
"amount": 1000,
|
||||||
"stock_uom": "Nos",
|
"stock_uom": "Nos",
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"item_code": "_Test FG Item",
|
||||||
|
"rm_item_code": "_Test Item Home Desktop 100",
|
||||||
|
"item_name": "_Test Item Home Desktop 100",
|
||||||
|
"qty": 20,
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"rate": 100,
|
||||||
|
"amount": 2000,
|
||||||
|
"stock_uom": "Nos",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
ste = frappe.get_doc(make_rm_stock_entry(sco.name, rm_items))
|
ste = frappe.get_doc(make_rm_stock_entry(sco.name, rm_items))
|
||||||
ste.to_warehouse = "_Test Warehouse 1 - _TC"
|
ste.to_warehouse = "_Test Warehouse 1 - _TC"
|
||||||
ste.save()
|
ste.save()
|
||||||
ste.submit()
|
ste.submit()
|
||||||
|
|
||||||
bin3 = frappe.db.get_value(
|
bin_after_rm_transfer = frappe.db.get_value(
|
||||||
"Bin",
|
"Bin",
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract",
|
fieldname="reserved_qty_for_sub_contract",
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(bin3.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
# reserved_qty_for_sub_contract should be decreased by 10
|
||||||
|
self.assertEqual(
|
||||||
make_stock_entry(
|
bin_after_rm_transfer.reserved_qty_for_sub_contract,
|
||||||
target="_Test Warehouse 1 - _TC", item_code="_Test Item", qty=40, basic_rate=100
|
bin_after_sco.reserved_qty_for_sub_contract - 10,
|
||||||
)
|
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse 1 - _TC",
|
|
||||||
item_code="_Test Item Home Desktop 100",
|
|
||||||
qty=40,
|
|
||||||
basic_rate=100,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Make SCR against the SCO
|
# Cancel Stock Entry(Send to Subcontractor)
|
||||||
scr = make_subcontracting_receipt(sco.name)
|
|
||||||
scr.save()
|
|
||||||
scr.submit()
|
|
||||||
|
|
||||||
bin4 = frappe.db.get_value(
|
|
||||||
"Bin",
|
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
|
||||||
fieldname="reserved_qty_for_sub_contract",
|
|
||||||
as_dict=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(bin4.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
|
||||||
|
|
||||||
# Cancel SCR
|
|
||||||
scr.reload()
|
|
||||||
scr.cancel()
|
|
||||||
bin5 = frappe.db.get_value(
|
|
||||||
"Bin",
|
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
|
||||||
fieldname="reserved_qty_for_sub_contract",
|
|
||||||
as_dict=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(bin5.reserved_qty_for_sub_contract, bin2.reserved_qty_for_sub_contract - 6)
|
|
||||||
|
|
||||||
# Cancel Stock Entry
|
|
||||||
ste.cancel()
|
ste.cancel()
|
||||||
bin6 = frappe.db.get_value(
|
bin_after_cancel_ste = frappe.db.get_value(
|
||||||
"Bin",
|
"Bin",
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract",
|
fieldname="reserved_qty_for_sub_contract",
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(bin6.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract + 10)
|
# reserved_qty_for_sub_contract should be increased by 10
|
||||||
|
self.assertEqual(
|
||||||
|
bin_after_cancel_ste.reserved_qty_for_sub_contract,
|
||||||
|
bin_after_rm_transfer.reserved_qty_for_sub_contract + 10,
|
||||||
|
)
|
||||||
|
|
||||||
# Cancel PO
|
# Cancel SCO
|
||||||
sco.reload()
|
sco.reload()
|
||||||
sco.cancel()
|
sco.cancel()
|
||||||
bin7 = frappe.db.get_value(
|
bin_after_cancel_sco = frappe.db.get_value(
|
||||||
"Bin",
|
"Bin",
|
||||||
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
filters={"warehouse": "_Test Warehouse - _TC", "item_code": "_Test Item"},
|
||||||
fieldname="reserved_qty_for_sub_contract",
|
fieldname="reserved_qty_for_sub_contract",
|
||||||
as_dict=1,
|
as_dict=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(bin7.reserved_qty_for_sub_contract, bin1.reserved_qty_for_sub_contract)
|
# reserved_qty_for_sub_contract should be decreased by 10
|
||||||
|
self.assertEqual(
|
||||||
|
bin_after_cancel_sco.reserved_qty_for_sub_contract,
|
||||||
|
bin_after_cancel_ste.reserved_qty_for_sub_contract - 10,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
bin_after_cancel_sco.reserved_qty_for_sub_contract, bin_before_sco.reserved_qty_for_sub_contract
|
||||||
|
)
|
||||||
|
|
||||||
def test_exploded_items(self):
|
def test_exploded_items(self):
|
||||||
item_code = "_Test Subcontracted FG Item 11"
|
item_code = "_Test Subcontracted FG Item 11"
|
||||||
|
@ -150,8 +150,7 @@
|
|||||||
"label": "Returned Qty",
|
"label": "Returned Qty",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1
|
||||||
"hidden": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "total_supplied_qty",
|
"fieldname": "total_supplied_qty",
|
||||||
@ -166,7 +165,7 @@
|
|||||||
"hide_toolbar": 1,
|
"hide_toolbar": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-07 12:58:28.208847",
|
"modified": "2022-08-26 16:04:56.125951",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Order Supplied Item",
|
"name": "Subcontracting Order Supplied Item",
|
||||||
|
@ -369,7 +369,7 @@
|
|||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "\nDraft\nCompleted\nReturn\nReturn Issued\nCancelled",
|
"options": "\nDraft\nCompleted\nReturn\nReturn Issued\nCancelled\nClosed",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_width": "150px",
|
"print_width": "150px",
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
@ -625,9 +625,10 @@
|
|||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"in_create": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-08-19 19:50:16.935124",
|
"modified": "2022-08-26 21:02:26.353870",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Receipt",
|
"name": "Subcontracting Receipt",
|
||||||
|
@ -77,6 +77,7 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
self.get_current_stock()
|
self.get_current_stock()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
|
self.validate_available_qty_for_consumption()
|
||||||
self.update_status_updater_args()
|
self.update_status_updater_args()
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.set_subcontracting_order_status()
|
self.set_subcontracting_order_status()
|
||||||
@ -109,10 +110,42 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
self.set_missing_values_in_supplied_items()
|
self.set_missing_values_in_supplied_items()
|
||||||
self.set_missing_values_in_items()
|
self.set_missing_values_in_items()
|
||||||
|
|
||||||
|
def set_available_qty_for_consumption(self):
|
||||||
|
supplied_items_details = {}
|
||||||
|
|
||||||
|
sco_supplied_item = frappe.qb.DocType("Subcontracting Order Supplied Item")
|
||||||
|
for item in self.get("items"):
|
||||||
|
supplied_items = (
|
||||||
|
frappe.qb.from_(sco_supplied_item)
|
||||||
|
.select(
|
||||||
|
sco_supplied_item.rm_item_code,
|
||||||
|
sco_supplied_item.reference_name,
|
||||||
|
(sco_supplied_item.total_supplied_qty - sco_supplied_item.consumed_qty).as_("available_qty"),
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
(sco_supplied_item.parent == item.subcontracting_order)
|
||||||
|
& (sco_supplied_item.main_item_code == item.item_code)
|
||||||
|
& (sco_supplied_item.reference_name == item.subcontracting_order_item)
|
||||||
|
)
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
|
if supplied_items:
|
||||||
|
supplied_items_details[item.name] = {}
|
||||||
|
|
||||||
|
for supplied_item in supplied_items:
|
||||||
|
supplied_items_details[item.name][supplied_item.rm_item_code] = supplied_item.available_qty
|
||||||
|
else:
|
||||||
|
for item in self.get("supplied_items"):
|
||||||
|
item.available_qty_for_consumption = supplied_items_details.get(item.reference_name, {}).get(
|
||||||
|
item.rm_item_code, 0
|
||||||
|
)
|
||||||
|
|
||||||
def set_missing_values_in_supplied_items(self):
|
def set_missing_values_in_supplied_items(self):
|
||||||
for item in self.get("supplied_items") or []:
|
for item in self.get("supplied_items") or []:
|
||||||
item.amount = item.rate * item.consumed_qty
|
item.amount = item.rate * item.consumed_qty
|
||||||
|
|
||||||
|
self.set_available_qty_for_consumption()
|
||||||
|
|
||||||
def set_missing_values_in_items(self):
|
def set_missing_values_in_items(self):
|
||||||
rm_supp_cost = {}
|
rm_supp_cost = {}
|
||||||
for item in self.get("supplied_items") or []:
|
for item in self.get("supplied_items") or []:
|
||||||
@ -149,6 +182,17 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
_("Rejected Warehouse is mandatory against rejected Item {0}").format(item.item_code)
|
_("Rejected Warehouse is mandatory against rejected Item {0}").format(item.item_code)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_available_qty_for_consumption(self):
|
||||||
|
for item in self.get("supplied_items"):
|
||||||
|
if (
|
||||||
|
item.available_qty_for_consumption and item.available_qty_for_consumption < item.consumed_qty
|
||||||
|
):
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Row {0}: Consumed Qty must be less than or equal to Available Qty For Consumption in Consumed Items Table."
|
||||||
|
).format(item.idx)
|
||||||
|
)
|
||||||
|
|
||||||
def set_items_cost_center(self):
|
def set_items_cost_center(self):
|
||||||
if self.company:
|
if self.company:
|
||||||
cost_center = frappe.get_cached_value("Company", self.company, "cost_center")
|
cost_center = frappe.get_cached_value("Company", self.company, "cost_center")
|
||||||
|
@ -73,6 +73,55 @@ class TestSubcontractingReceipt(FrappeTestCase):
|
|||||||
rm_supp_cost = sum(item.amount for item in scr.get("supplied_items"))
|
rm_supp_cost = sum(item.amount for item in scr.get("supplied_items"))
|
||||||
self.assertEqual(scr.get("items")[0].rm_supp_cost, flt(rm_supp_cost))
|
self.assertEqual(scr.get("items")[0].rm_supp_cost, flt(rm_supp_cost))
|
||||||
|
|
||||||
|
def test_available_qty_for_consumption(self):
|
||||||
|
make_stock_entry(
|
||||||
|
item_code="_Test Item", qty=100, target="_Test Warehouse 1 - _TC", basic_rate=100
|
||||||
|
)
|
||||||
|
make_stock_entry(
|
||||||
|
item_code="_Test Item Home Desktop 100",
|
||||||
|
qty=100,
|
||||||
|
target="_Test Warehouse 1 - _TC",
|
||||||
|
basic_rate=100,
|
||||||
|
)
|
||||||
|
service_items = [
|
||||||
|
{
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"item_code": "Subcontracted Service Item 1",
|
||||||
|
"qty": 10,
|
||||||
|
"rate": 100,
|
||||||
|
"fg_item": "_Test FG Item",
|
||||||
|
"fg_item_qty": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
sco = get_subcontracting_order(service_items=service_items)
|
||||||
|
rm_items = [
|
||||||
|
{
|
||||||
|
"main_item_code": "_Test FG Item",
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"qty": 5.0,
|
||||||
|
"rate": 100.0,
|
||||||
|
"stock_uom": "_Test UOM",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"main_item_code": "_Test FG Item",
|
||||||
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
|
"qty": 10.0,
|
||||||
|
"rate": 100.0,
|
||||||
|
"stock_uom": "_Test UOM",
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
|
scr.save()
|
||||||
|
self.assertRaises(frappe.ValidationError, scr.submit)
|
||||||
|
|
||||||
def test_subcontracting_gle_fg_item_rate_zero(self):
|
def test_subcontracting_gle_fg_item_rate_zero(self):
|
||||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"col_break2",
|
"col_break2",
|
||||||
"amount",
|
"amount",
|
||||||
"secbreak_2",
|
"secbreak_2",
|
||||||
|
"available_qty_for_consumption",
|
||||||
"required_qty",
|
"required_qty",
|
||||||
"col_break3",
|
"col_break3",
|
||||||
"consumed_qty",
|
"consumed_qty",
|
||||||
@ -75,8 +76,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "required_qty",
|
"fieldname": "required_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"label": "Required Qty",
|
||||||
"label": "Available Qty For Consumption",
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
@ -85,7 +85,7 @@
|
|||||||
"fieldname": "consumed_qty",
|
"fieldname": "consumed_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Qty to be Consumed",
|
"label": "Consumed Qty",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -179,12 +179,21 @@
|
|||||||
"options": "Subcontracting Order",
|
"options": "Subcontracting Order",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "available_qty_for_consumption",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Available Qty For Consumption",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-18 10:45:16.538479",
|
"modified": "2022-09-02 22:28:53.392381",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Subcontracting",
|
"module": "Subcontracting",
|
||||||
"name": "Subcontracting Receipt Supplied Item",
|
"name": "Subcontracting Receipt Supplied Item",
|
||||||
@ -193,6 +202,6 @@
|
|||||||
"permissions": [],
|
"permissions": [],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1,
|
"states": [],
|
||||||
"states": []
|
"track_changes": 1
|
||||||
}
|
}
|
@ -5,14 +5,13 @@ import json
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint, cstr
|
from frappe.utils import cint, cstr
|
||||||
from redisearch import AutoCompleter, Client, Query
|
from redis.commands.search.query import Query
|
||||||
|
|
||||||
from erpnext.e_commerce.redisearch_utils import (
|
from erpnext.e_commerce.redisearch_utils import (
|
||||||
WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE,
|
WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE,
|
||||||
WEBSITE_ITEM_INDEX,
|
WEBSITE_ITEM_INDEX,
|
||||||
WEBSITE_ITEM_NAME_AUTOCOMPLETE,
|
WEBSITE_ITEM_NAME_AUTOCOMPLETE,
|
||||||
is_redisearch_enabled,
|
is_redisearch_enabled,
|
||||||
make_key,
|
|
||||||
)
|
)
|
||||||
from erpnext.e_commerce.shopping_cart.product_info import set_product_info_for_website
|
from erpnext.e_commerce.shopping_cart.product_info import set_product_info_for_website
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
|
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
|
||||||
@ -88,15 +87,17 @@ def product_search(query, limit=10, fuzzy_search=True):
|
|||||||
if not query:
|
if not query:
|
||||||
return search_results
|
return search_results
|
||||||
|
|
||||||
red = frappe.cache()
|
redis = frappe.cache()
|
||||||
query = clean_up_query(query)
|
query = clean_up_query(query)
|
||||||
|
|
||||||
# TODO: Check perf/correctness with Suggestions & Query vs only Query
|
# TODO: Check perf/correctness with Suggestions & Query vs only Query
|
||||||
# TODO: Use Levenshtein Distance in Query (max=3)
|
# TODO: Use Levenshtein Distance in Query (max=3)
|
||||||
ac = AutoCompleter(make_key(WEBSITE_ITEM_NAME_AUTOCOMPLETE), conn=red)
|
redisearch = redis.ft(WEBSITE_ITEM_INDEX)
|
||||||
client = Client(make_key(WEBSITE_ITEM_INDEX), conn=red)
|
suggestions = redisearch.sugget(
|
||||||
suggestions = ac.get_suggestions(
|
WEBSITE_ITEM_NAME_AUTOCOMPLETE,
|
||||||
query, num=limit, fuzzy=fuzzy_search and len(query) > 3 # Fuzzy on length < 3 can be real slow
|
query,
|
||||||
|
num=limit,
|
||||||
|
fuzzy=fuzzy_search and len(query) > 3,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Build a query
|
# Build a query
|
||||||
@ -106,8 +107,8 @@ def product_search(query, limit=10, fuzzy_search=True):
|
|||||||
query_string += f"|('{clean_up_query(s.string)}')"
|
query_string += f"|('{clean_up_query(s.string)}')"
|
||||||
|
|
||||||
q = Query(query_string)
|
q = Query(query_string)
|
||||||
|
results = redisearch.search(q)
|
||||||
|
|
||||||
results = client.search(q)
|
|
||||||
search_results["results"] = list(map(convert_to_dict, results.docs))
|
search_results["results"] = list(map(convert_to_dict, results.docs))
|
||||||
search_results["results"] = sorted(
|
search_results["results"] = sorted(
|
||||||
search_results["results"], key=lambda k: frappe.utils.cint(k["ranking"]), reverse=True
|
search_results["results"], key=lambda k: frappe.utils.cint(k["ranking"]), reverse=True
|
||||||
@ -141,8 +142,8 @@ def get_category_suggestions(query):
|
|||||||
if not query:
|
if not query:
|
||||||
return search_results
|
return search_results
|
||||||
|
|
||||||
ac = AutoCompleter(make_key(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE), conn=frappe.cache())
|
ac = frappe.cache().ft()
|
||||||
suggestions = ac.get_suggestions(query, num=10, with_payloads=True)
|
suggestions = ac.sugget(WEBSITE_ITEM_CATEGORY_AUTOCOMPLETE, query, num=10, with_payloads=True)
|
||||||
|
|
||||||
results = [json.loads(s.payload) for s in suggestions]
|
results = [json.loads(s.payload) for s in suggestions]
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ All other ITC,Alle anderen ITC,
|
|||||||
All the mandatory Task for employee creation hasn't been done yet.,Alle obligatorischen Aufgaben zur Mitarbeitererstellung wurden noch nicht erledigt.,
|
All the mandatory Task for employee creation hasn't been done yet.,Alle obligatorischen Aufgaben zur Mitarbeitererstellung wurden noch nicht erledigt.,
|
||||||
Allocate Payment Amount,Zahlungsbetrag zuweisen,
|
Allocate Payment Amount,Zahlungsbetrag zuweisen,
|
||||||
Allocated Amount,Zugewiesene Menge,
|
Allocated Amount,Zugewiesene Menge,
|
||||||
Allocated Leaves,Zugewiesene Blätter,
|
Allocated Leaves,Zugewiesene Urlaubstage,
|
||||||
Allocating leaves...,Blätter zuordnen...,
|
Allocating leaves...,Blätter zuordnen...,
|
||||||
Already record exists for the item {0},Es existiert bereits ein Datensatz für den Artikel {0},
|
Already record exists for the item {0},Es existiert bereits ein Datensatz für den Artikel {0},
|
||||||
"Already set default in pos profile {0} for user {1}, kindly disabled default","Im Standardprofil {0} für den Benutzer {1} ist der Standard bereits festgelegt, standardmäßig deaktiviert",
|
"Already set default in pos profile {0} for user {1}, kindly disabled default","Im Standardprofil {0} für den Benutzer {1} ist der Standard bereits festgelegt, standardmäßig deaktiviert",
|
||||||
@ -8623,8 +8623,8 @@ Material Request Warehouse,Materialanforderungslager,
|
|||||||
Select warehouse for material requests,Wählen Sie Lager für Materialanfragen,
|
Select warehouse for material requests,Wählen Sie Lager für Materialanfragen,
|
||||||
Transfer Materials For Warehouse {0},Material für Lager übertragen {0},
|
Transfer Materials For Warehouse {0},Material für Lager übertragen {0},
|
||||||
Production Plan Material Request Warehouse,Produktionsplan Materialanforderungslager,
|
Production Plan Material Request Warehouse,Produktionsplan Materialanforderungslager,
|
||||||
Sets 'Source Warehouse' in each row of the items table.,Legt 'Source Warehouse' in jeder Zeile der Artikeltabelle fest.,
|
Sets 'Source Warehouse' in each row of the items table.,Legt in jeder Zeile der Artikeltabelle das „Ausgangslager“ fest.,
|
||||||
Sets 'Target Warehouse' in each row of the items table.,"Füllt das Feld ""Ziel Lager"" in allen Positionen der folgenden Tabelle.",
|
Sets 'Target Warehouse' in each row of the items table.,Legt in jeder Zeile der Artikeltabelle das „Eingangslager“ fest.,
|
||||||
Show Cancelled Entries,Abgebrochene Einträge anzeigen,
|
Show Cancelled Entries,Abgebrochene Einträge anzeigen,
|
||||||
Backdated Stock Entry,Backdated Stock Entry,
|
Backdated Stock Entry,Backdated Stock Entry,
|
||||||
Row #{}: Currency of {} - {} doesn't matches company currency.,Zeile # {}: Die Währung von {} - {} stimmt nicht mit der Firmenwährung überein.,
|
Row #{}: Currency of {} - {} doesn't matches company currency.,Zeile # {}: Die Währung von {} - {} stimmt nicht mit der Firmenwährung überein.,
|
||||||
@ -9871,3 +9871,31 @@ Leave Type Allocation,Zuordnung Abwesenheitsarten,
|
|||||||
From Lead,Aus Lead,
|
From Lead,Aus Lead,
|
||||||
From Opportunity,Aus Chance,
|
From Opportunity,Aus Chance,
|
||||||
Publish in Website,Auf Webseite veröffentlichen,
|
Publish in Website,Auf Webseite veröffentlichen,
|
||||||
|
Total Allocated Leave(s),Gesamte zugewiesene Urlaubstage,
|
||||||
|
Expired Leave(s),Verfallene Urlaubstage,
|
||||||
|
Used Leave(s),Verbrauchte Urlaubstage,
|
||||||
|
Leave(s) Pending Approval,Urlaubstage zur Genehmigung ausstehend,
|
||||||
|
Available Leave(s),Verfügbare Urlaubstage,
|
||||||
|
Party Specific Item,Parteispezifischer Artikel,
|
||||||
|
Active Customers,Aktive Kunden,
|
||||||
|
Annual Sales,Jährlicher Umsatz,
|
||||||
|
Total Outgoing Bills,Ausgangsrechnungen insgesamt,
|
||||||
|
Total Incoming Bills,Eingangsrechnungen insgesamt,
|
||||||
|
Total Incoming Payment,Zahlungseingang insgesamt,
|
||||||
|
Total Outgoing Payment,Zahlungsausgang insgesamt,
|
||||||
|
Incoming Bills (Purchase Invoice),Eingehende Rechnungen (Eingangsrechnung),
|
||||||
|
Outgoing Bills (Sales Invoice),Ausgehende Rechnungen (Ausgangsrechnung),
|
||||||
|
Accounts Receivable Ageing,Fälligkeit Forderungen,
|
||||||
|
Accounts Payable Ageing,Fälligkeit Verbindlichkeiten,
|
||||||
|
Budget Variance,Budgetabweichung,
|
||||||
|
Based On Value,Basierend auf Wert,
|
||||||
|
Restrict Items Based On,Artikel einschränken auf Basis von,
|
||||||
|
Earnings & Deductions,Erträge & Abzüge,
|
||||||
|
Is Process Loss,Ist Prozessverlust,
|
||||||
|
Is Finished Item,Ist fertiger Artikel,
|
||||||
|
Is Scrap Item,Ist Schrott,
|
||||||
|
Issue a debit note with 0 qty against an existing Sales Invoice,Lastschrift mit Menge 0 gegen eine bestehende Ausgangsrechnung ausstellen,
|
||||||
|
Show Remarks,Bemerkungen anzeigen,
|
||||||
|
Website Item,Webseiten-Artikel,
|
||||||
|
Update Property,Eigenschaft aktualisieren,
|
||||||
|
Recurring Sales Invoice,Wiederkehrende Ausgangsrechnung,
|
||||||
|
Can't render this file because it is too large.
|
@ -329,11 +329,11 @@ Average Rate,Prix moyen,
|
|||||||
Avg Daily Outgoing,Moy Quotidienne Sortante,
|
Avg Daily Outgoing,Moy Quotidienne Sortante,
|
||||||
Avg. Buying Price List Rate,Moyenne de la liste de prix d'achat,
|
Avg. Buying Price List Rate,Moyenne de la liste de prix d'achat,
|
||||||
Avg. Selling Price List Rate,Prix moyen de la liste de prix de vente,
|
Avg. Selling Price List Rate,Prix moyen de la liste de prix de vente,
|
||||||
Avg. Selling Rate,Moy. Taux de vente,
|
Avg. Selling Rate,Moy. prix de vente,
|
||||||
BOM,Nomenclature,
|
BOM,Nomenclature,
|
||||||
BOM Browser,Explorateur Nomenclature,
|
BOM Browser,Explorateur Nomenclature,
|
||||||
BOM No,N° Nomenclature,
|
BOM No,N° Nomenclature,
|
||||||
BOM Rate,Valeur nomenclature,
|
BOM Rate,Cout nomenclature,
|
||||||
BOM Stock Report,Rapport de Stock des nomenclatures,
|
BOM Stock Report,Rapport de Stock des nomenclatures,
|
||||||
BOM and Manufacturing Quantity are required,Nomenclature et quantité de production sont nécessaires,
|
BOM and Manufacturing Quantity are required,Nomenclature et quantité de production sont nécessaires,
|
||||||
BOM does not contain any stock item,Nomenclature ne contient aucun article en stock,
|
BOM does not contain any stock item,Nomenclature ne contient aucun article en stock,
|
||||||
@ -561,9 +561,9 @@ Colour,Couleur,
|
|||||||
Combined invoice portion must equal 100%,La portion combinée de la facture doit être égale à 100%,
|
Combined invoice portion must equal 100%,La portion combinée de la facture doit être égale à 100%,
|
||||||
Commercial,Commercial,
|
Commercial,Commercial,
|
||||||
Commission,Commission,
|
Commission,Commission,
|
||||||
Commission Rate %,Taux de commission%,
|
Commission Rate %,Pourcentage de commission,
|
||||||
Commission on Sales,Commission sur les ventes,
|
Commission on Sales,Commission sur les ventes,
|
||||||
Commission rate cannot be greater than 100,Taux de commission ne peut pas être supérieure à 100,
|
Commission rate cannot be greater than 100,Pourcentage de commission ne peut pas être supérieure à 100,
|
||||||
Community Forum,Forum de la communauté,
|
Community Forum,Forum de la communauté,
|
||||||
Company (not Customer or Supplier) master.,Données de base de la Société (ni les Clients ni les Fournisseurs),
|
Company (not Customer or Supplier) master.,Données de base de la Société (ni les Clients ni les Fournisseurs),
|
||||||
Company Abbreviation,Abréviation de la Société,
|
Company Abbreviation,Abréviation de la Société,
|
||||||
@ -658,7 +658,7 @@ 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 une piste,
|
Create Lead,Créer un Prospect,
|
||||||
Create Leads,Créer des Prospects,
|
Create Leads,Créer des Prospects,
|
||||||
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,
|
||||||
@ -1072,7 +1072,7 @@ For Warehouse is required before Submit,Pour l’Entrepôt est requis avant de V
|
|||||||
"For an item {0}, quantity must be negative number","Pour l'article {0}, la quantité doit être un nombre négatif",
|
"For an item {0}, quantity must be negative number","Pour l'article {0}, la quantité doit être un nombre négatif",
|
||||||
"For an item {0}, quantity must be positive number","Pour un article {0}, la quantité doit être un nombre positif",
|
"For an item {0}, quantity must be positive number","Pour un article {0}, la quantité doit être un nombre positif",
|
||||||
"For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry","Pour la carte de travail {0}, vous pouvez uniquement saisir une entrée de stock de type "Transfert d'article pour fabrication".",
|
"For job card {0}, you can only make the 'Material Transfer for Manufacture' type stock entry","Pour la carte de travail {0}, vous pouvez uniquement saisir une entrée de stock de type "Transfert d'article pour fabrication".",
|
||||||
"For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included","Pour la ligne {0} dans {1}. Pour inclure {2} dans le prix de l'Article, les lignes {3} doivent également être incluses",
|
"For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included","Pour la ligne {0} dans {1}. Pour inclure {2} dans le prix de l'article, les lignes {3} doivent également être incluses",
|
||||||
For row {0}: Enter Planned Qty,Pour la ligne {0}: entrez la quantité planifiée,
|
For row {0}: Enter Planned Qty,Pour la ligne {0}: entrez la quantité planifiée,
|
||||||
"For {0}, only credit accounts can be linked against another debit entry","Pour {0}, seuls les comptes de crédit peuvent être liés avec une autre écriture de débit",
|
"For {0}, only credit accounts can be linked against another debit entry","Pour {0}, seuls les comptes de crédit peuvent être liés avec une autre écriture de débit",
|
||||||
"For {0}, only debit accounts can be linked against another credit entry","Pour {0}, seuls les comptes de débit peuvent être liés avec une autre écriture de crédit",
|
"For {0}, only debit accounts can be linked against another credit entry","Pour {0}, seuls les comptes de débit peuvent être liés avec une autre écriture de crédit",
|
||||||
@ -1235,7 +1235,7 @@ ITC Reversed,CTI inversé,
|
|||||||
Identifying Decision Makers,Identifier les décideurs,
|
Identifying Decision Makers,Identifier les décideurs,
|
||||||
"If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)","Si l'option adhésion automatique est cochée, les clients seront automatiquement liés au programme de fidélité concerné (après l'enregistrement)",
|
"If Auto Opt In is checked, then the customers will be automatically linked with the concerned Loyalty Program (on save)","Si l'option adhésion automatique est cochée, les clients seront automatiquement liés au programme de fidélité concerné (après l'enregistrement)",
|
||||||
"If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.","Si plusieurs Règles de Prix continuent de prévaloir, les utilisateurs sont invités à définir manuellement la priorité pour résoudre les conflits.",
|
"If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.","Si plusieurs Règles de Prix continuent de prévaloir, les utilisateurs sont invités à définir manuellement la priorité pour résoudre les conflits.",
|
||||||
"If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.","Si la règle de tarification sélectionnée est définie pour le «Prix Unitaire», elle écrase la liste de prix. Le prix unitaire de la règle de tarification est le prix unitaire final, donc aucune autre réduction supplémentaire ne doit être appliquée. Par conséquent, dans les transactions telles que la commande client, la commande d'achat, etc., elle sera récupérée dans le champ ""Prix Unitaire"", plutôt que dans le champ ""Tarif de la liste de prix"".",
|
"If selected Pricing Rule is made for 'Rate', it will overwrite Price List. Pricing Rule rate is the final rate, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field.","Si la règle de tarification sélectionnée est définie pour le 'Prix Unitaire', elle écrase la liste de prix. Le prix unitaire de la règle de tarification est le prix unitaire final, donc aucune autre réduction supplémentaire ne doit être appliquée. Par conséquent, dans les transactions telles que la commande client, la commande d'achat, etc., elle sera récupérée dans le champ 'Prix Unitaire', plutôt que dans le champ 'Tarif de la liste de prix'.",
|
||||||
"If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.","Si deux Règles de Prix ou plus sont trouvées sur la base des conditions ci-dessus, une Priorité est appliquée. La Priorité est un nombre compris entre 0 et 20 avec une valeur par défaut de zéro (vide). Les nombres les plus élévés sont prioritaires s'il y a plusieurs Règles de Prix avec mêmes conditions.",
|
"If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.","Si deux Règles de Prix ou plus sont trouvées sur la base des conditions ci-dessus, une Priorité est appliquée. La Priorité est un nombre compris entre 0 et 20 avec une valeur par défaut de zéro (vide). Les nombres les plus élévés sont prioritaires s'il y a plusieurs Règles de Prix avec mêmes conditions.",
|
||||||
"If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.","Si vous souhaitez ne pas mettre de date d'expiration pour les points de fidélité, laissez la durée d'expiration vide ou mettez 0.",
|
"If unlimited expiry for the Loyalty Points, keep the Expiry Duration empty or 0.","Si vous souhaitez ne pas mettre de date d'expiration pour les points de fidélité, laissez la durée d'expiration vide ou mettez 0.",
|
||||||
"If you have any questions, please get back to us.","Si vous avez des questions, veuillez revenir vers nous.",
|
"If you have any questions, please get back to us.","Si vous avez des questions, veuillez revenir vers nous.",
|
||||||
@ -1269,7 +1269,7 @@ Income,Revenus,
|
|||||||
Income Account,Compte de Produits,
|
Income Account,Compte de Produits,
|
||||||
Income Tax,Impôt sur le revenu,
|
Income Tax,Impôt sur le revenu,
|
||||||
Incoming,Entrant,
|
Incoming,Entrant,
|
||||||
Incoming Rate,Taux d'Entrée,
|
Incoming Rate,Prix d'Entrée,
|
||||||
Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction.,Nombre incorrect d'Écritures Grand Livre trouvées. Vous avez peut-être choisi le mauvais Compte dans la transaction.,
|
Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction.,Nombre incorrect d'Écritures Grand Livre trouvées. Vous avez peut-être choisi le mauvais Compte dans la transaction.,
|
||||||
Increment cannot be 0,Incrément ne peut pas être 0,
|
Increment cannot be 0,Incrément ne peut pas être 0,
|
||||||
Increment for Attribute {0} cannot be 0,Incrément pour l'Attribut {0} ne peut pas être 0,
|
Increment for Attribute {0} cannot be 0,Incrément pour l'Attribut {0} ne peut pas être 0,
|
||||||
@ -1365,7 +1365,7 @@ Item Variants,Variantes de l'Article,
|
|||||||
Item Variants updated,Variantes d'article mises à jour,
|
Item Variants updated,Variantes d'article mises à jour,
|
||||||
Item has variants.,L'article a des variantes.,
|
Item has variants.,L'article a des variantes.,
|
||||||
Item must be added using 'Get Items from Purchase Receipts' button,L'article doit être ajouté à l'aide du bouton 'Obtenir des éléments de Reçus d'Achat',
|
Item must be added using 'Get Items from Purchase Receipts' button,L'article doit être ajouté à l'aide du bouton 'Obtenir des éléments de Reçus d'Achat',
|
||||||
Item valuation rate is recalculated considering landed cost voucher amount,Le taux d'évaluation de l'article est recalculé compte tenu du montant du bon de prix au débarquement,
|
Item valuation rate is recalculated considering landed cost voucher amount,Le taux de valorisation de l'article est recalculé compte tenu du montant du bon de prix au débarquement,
|
||||||
Item variant {0} exists with same attributes,La variante de l'article {0} existe avec les mêmes caractéristiques,
|
Item variant {0} exists with same attributes,La variante de l'article {0} existe avec les mêmes caractéristiques,
|
||||||
Item {0} does not exist,Article {0} n'existe pas,
|
Item {0} does not exist,Article {0} n'existe pas,
|
||||||
Item {0} does not exist in the system or has expired,L'article {0} n'existe pas dans le système ou a expiré,
|
Item {0} does not exist in the system or has expired,L'article {0} n'existe pas dans le système ou a expiré,
|
||||||
@ -2147,7 +2147,7 @@ Previous Financial Year is not closed,L’Exercice Financier Précédent n’est
|
|||||||
Price,Prix,
|
Price,Prix,
|
||||||
Price List,Liste de prix,
|
Price List,Liste de prix,
|
||||||
Price List Currency not selected,Devise de la Liste de Prix non sélectionnée,
|
Price List Currency not selected,Devise de la Liste de Prix non sélectionnée,
|
||||||
Price List Rate,Taux de la Liste des Prix,
|
Price List Rate,Prix de la Liste des Prix,
|
||||||
Price List master.,Données de Base des Listes de Prix,
|
Price List master.,Données de Base des Listes de Prix,
|
||||||
Price List must be applicable for Buying or Selling,La Liste de Prix doit être applicable pour les Achats et les Ventes,
|
Price List must be applicable for Buying or Selling,La Liste de Prix doit être applicable pour les Achats et les Ventes,
|
||||||
Price List {0} is disabled or does not exist,Liste des Prix {0} est désactivée ou n'existe pas,
|
Price List {0} is disabled or does not exist,Liste des Prix {0} est désactivée ou n'existe pas,
|
||||||
@ -2288,8 +2288,8 @@ Quotations: ,Devis :,
|
|||||||
Quotes to Leads or Customers.,Devis de Prospects ou Clients.,
|
Quotes to Leads or Customers.,Devis de Prospects 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,Taux,
|
Rate,Prix,
|
||||||
Rate:,Taux:,
|
Rate:,Prix:,
|
||||||
Rating,Évaluation,
|
Rating,Évaluation,
|
||||||
Raw Material,Matières Premières,
|
Raw Material,Matières Premières,
|
||||||
Raw Materials,Matières premières,
|
Raw Materials,Matières premières,
|
||||||
@ -2426,7 +2426,7 @@ Route,Route,
|
|||||||
Row # {0}: ,Ligne # {0} :,
|
Row # {0}: ,Ligne # {0} :,
|
||||||
Row # {0}: Batch No must be same as {1} {2},Ligne # {0} : Le N° de Lot doit être le même que {1} {2},
|
Row # {0}: Batch No must be same as {1} {2},Ligne # {0} : Le N° de Lot doit être le même que {1} {2},
|
||||||
Row # {0}: Cannot return more than {1} for Item {2},Ligne # {0} : Vous ne pouvez pas retourner plus de {1} pour l’Article {2},
|
Row # {0}: Cannot return more than {1} for Item {2},Ligne # {0} : Vous ne pouvez pas retourner plus de {1} pour l’Article {2},
|
||||||
Row # {0}: Rate cannot be greater than the rate used in {1} {2},Ligne # {0}: Le Taux ne peut pas être supérieur au taux utilisé dans {1} {2},
|
Row # {0}: Rate cannot be greater than the rate used in {1} {2},Ligne # {0}: Le prix ne peut pas être supérieur au prix utilisé dans {1} {2},
|
||||||
Row # {0}: Serial No is mandatory,Ligne # {0} : N° de série est obligatoire,
|
Row # {0}: Serial No is mandatory,Ligne # {0} : N° de série est obligatoire,
|
||||||
Row # {0}: Serial No {1} does not match with {2} {3},Ligne # {0} : N° de série {1} ne correspond pas à {2} {3},
|
Row # {0}: Serial No {1} does not match with {2} {3},Ligne # {0} : N° de série {1} ne correspond pas à {2} {3},
|
||||||
Row #{0} (Payment Table): Amount must be negative,Row # {0} (Table de paiement): le montant doit être négatif,
|
Row #{0} (Payment Table): Amount must be negative,Row # {0} (Table de paiement): le montant doit être négatif,
|
||||||
@ -2434,7 +2434,7 @@ Row #{0} (Payment Table): Amount must be positive,Ligne #{0} (Table de paiement)
|
|||||||
Row #{0}: Account {1} does not belong to company {2},Ligne # {0}: le compte {1} n'appartient pas à la société {2},
|
Row #{0}: Account {1} does not belong to company {2},Ligne # {0}: le compte {1} n'appartient pas à la société {2},
|
||||||
Row #{0}: Allocated Amount cannot be greater than outstanding amount.,Ligne # {0}: montant attribué ne peut pas être supérieur au montant en souffrance.,
|
Row #{0}: Allocated Amount cannot be greater than outstanding amount.,Ligne # {0}: montant attribué ne peut pas être supérieur au montant en souffrance.,
|
||||||
"Row #{0}: Asset {1} cannot be submitted, it is already {2}","Ligne #{0} : L’Actif {1} ne peut pas être soumis, il est déjà {2}",
|
"Row #{0}: Asset {1} cannot be submitted, it is already {2}","Ligne #{0} : L’Actif {1} ne peut pas être soumis, il est déjà {2}",
|
||||||
Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.,Ligne n ° {0}: impossible de définir le tarif si le montant est supérieur au montant facturé pour l'élément {1}.,
|
Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.,Ligne n ° {0}: impossible de définir le prix si le montant est supérieur au montant facturé pour l'élément {1}.,
|
||||||
Row #{0}: Clearance date {1} cannot be before Cheque Date {2},Ligne #{0} : Date de compensation {1} ne peut pas être antérieure à la Date du Chèque {2},
|
Row #{0}: Clearance date {1} cannot be before Cheque Date {2},Ligne #{0} : Date de compensation {1} ne peut pas être antérieure à la Date du Chèque {2},
|
||||||
Row #{0}: Duplicate entry in References {1} {2},Ligne # {0}: entrée en double dans les références {1} {2},
|
Row #{0}: Duplicate entry in References {1} {2},Ligne # {0}: entrée en double dans les références {1} {2},
|
||||||
Row #{0}: Expected Delivery Date cannot be before Purchase Order Date,Ligne {0}: la date de livraison prévue ne peut pas être avant la date de commande,
|
Row #{0}: Expected Delivery Date cannot be before Purchase Order Date,Ligne {0}: la date de livraison prévue ne peut pas être avant la date de commande,
|
||||||
@ -2898,7 +2898,7 @@ Sync has been temporarily disabled because maximum retries have been exceeded,La
|
|||||||
Syntax error in condition: {0},Erreur de syntaxe dans la condition: {0},
|
Syntax error in condition: {0},Erreur de syntaxe dans la condition: {0},
|
||||||
Syntax error in formula or condition: {0},Erreur de syntaxe dans la formule ou condition : {0},
|
Syntax error in formula or condition: {0},Erreur de syntaxe dans la formule ou condition : {0},
|
||||||
System Manager,Responsable Système,
|
System Manager,Responsable Système,
|
||||||
TDS Rate %,Taux de TDS%,
|
TDS Rate %,Pourcentage de TDS,
|
||||||
Tap items to add them here,Choisissez des articles pour les ajouter ici,
|
Tap items to add them here,Choisissez des articles pour les ajouter ici,
|
||||||
Target,Cible,
|
Target,Cible,
|
||||||
Target ({}),Cible ({}),
|
Target ({}),Cible ({}),
|
||||||
@ -3190,7 +3190,7 @@ Update Print Format,Mettre à Jour le Format d'Impression,
|
|||||||
Update Response,Mettre à jour la réponse,
|
Update Response,Mettre à jour la réponse,
|
||||||
Update bank payment dates with journals.,Mettre à jour les dates de paiement bancaires avec les journaux.,
|
Update bank payment dates with journals.,Mettre à jour les dates de paiement bancaires avec les journaux.,
|
||||||
Update in progress. It might take a while.,Mise à jour en cours. Ça peut prendre un moment.,
|
Update in progress. It might take a while.,Mise à jour en cours. Ça peut prendre un moment.,
|
||||||
Update rate as per last purchase,Taux de mise à jour selon le dernier achat,
|
Update rate as per last purchase,Mettre à jour les prix selon le dernier prix achat,
|
||||||
Update stock must be enable for the purchase invoice {0},La mise à jour du stock doit être activée pour la facture d'achat {0},
|
Update stock must be enable for the purchase invoice {0},La mise à jour du stock doit être activée pour la facture d'achat {0},
|
||||||
Updating Variants...,Mise à jour des variantes ...,
|
Updating Variants...,Mise à jour des variantes ...,
|
||||||
Upload your letter head and logo. (you can edit them later).,Charger votre en-tête et logo. (vous pouvez les modifier ultérieurement).,
|
Upload your letter head and logo. (you can edit them later).,Charger votre en-tête et logo. (vous pouvez les modifier ultérieurement).,
|
||||||
@ -3326,7 +3326,6 @@ You are not authorized to add or update entries before {0},Vous n'êtes pas auto
|
|||||||
You are not authorized to approve leaves on Block Dates,Vous n'êtes pas autorisé à approuver les congés sur les Dates Bloquées,
|
You are not authorized to approve leaves on Block Dates,Vous n'êtes pas autorisé à approuver les congés sur les Dates Bloquées,
|
||||||
You are not authorized to set Frozen value,Vous n'êtes pas autorisé à définir des valeurs gelées,
|
You are not authorized to set Frozen value,Vous n'êtes pas autorisé à définir des valeurs gelées,
|
||||||
You are not present all day(s) between compensatory leave request days,Vous n'êtes pas présent(e) tous les jours vos demandes de congé compensatoire,
|
You are not present all day(s) between compensatory leave request days,Vous n'êtes pas présent(e) tous les jours vos demandes de congé compensatoire,
|
||||||
You can not change rate if BOM mentioned agianst any item,Vous ne pouvez pas modifier le taux si la nomenclature est mentionnée pour un article,
|
|
||||||
You can not enter current voucher in 'Against Journal Entry' column,Vous ne pouvez pas entrer le bon actuel dans la colonne 'Pour l'Écriture de Journal',
|
You can not enter current voucher in 'Against Journal Entry' column,Vous ne pouvez pas entrer le bon actuel dans la colonne 'Pour l'Écriture de Journal',
|
||||||
You can only have Plans with the same billing cycle in a Subscription,Vous ne pouvez avoir que des plans ayant le même cycle de facturation dans le même abonnement,
|
You can only have Plans with the same billing cycle in a Subscription,Vous ne pouvez avoir que des plans ayant le même cycle de facturation dans le même abonnement,
|
||||||
You can only redeem max {0} points in this order.,Vous pouvez uniquement échanger un maximum de {0} points dans cet commande.,
|
You can only redeem max {0} points in this order.,Vous pouvez uniquement échanger un maximum de {0} points dans cet commande.,
|
||||||
@ -3882,7 +3881,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 fil,
|
Open Lead,Ouvrir le Prospect,
|
||||||
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,
|
||||||
@ -3971,7 +3970,7 @@ Queued,File d'Attente,
|
|||||||
Quick Entry,Écriture Rapide,
|
Quick Entry,Écriture Rapide,
|
||||||
Quiz {0} does not exist,Le questionnaire {0} n'existe pas,
|
Quiz {0} does not exist,Le questionnaire {0} n'existe pas,
|
||||||
Quotation Amount,Montant du devis,
|
Quotation Amount,Montant du devis,
|
||||||
Rate or Discount is required for the price discount.,Le taux ou la remise est requis pour la remise de prix.,
|
Rate or Discount is required for the price discount.,Le prix ou la remise est requis pour la remise.,
|
||||||
Reason,Raison,
|
Reason,Raison,
|
||||||
Reconcile Entries,Réconcilier les entrées,
|
Reconcile Entries,Réconcilier les entrées,
|
||||||
Reconcile this account,Réconcilier ce compte,
|
Reconcile this account,Réconcilier ce compte,
|
||||||
@ -4348,7 +4347,7 @@ Valid Upto date cannot be before Valid From date,La date de validité valide ne
|
|||||||
Valid From date not in Fiscal Year {0},Date de début de validité non comprise dans l'exercice {0},
|
Valid From date not in Fiscal Year {0},Date de début de validité non comprise dans l'exercice {0},
|
||||||
Valid Upto date not in Fiscal Year {0},Valable jusqu'à la date hors exercice {0},
|
Valid Upto date not in Fiscal Year {0},Valable jusqu'à la date hors exercice {0},
|
||||||
Group Roll No,Groupe Roll Non,
|
Group Roll No,Groupe Roll Non,
|
||||||
Maintain Same Rate Throughout Sales Cycle,Maintenir le Même Taux Durant le Cycle de Vente,
|
Maintain Same Rate Throughout Sales Cycle,Maintenir le même prix Durant le Cycle de Vente,
|
||||||
"Row {1}: Quantity ({0}) cannot be a fraction. To allow this, disable '{2}' in UOM {3}.","Ligne {1}: la quantité ({0}) ne peut pas être une fraction. Pour autoriser cela, désactivez «{2}» dans UdM {3}.",
|
"Row {1}: Quantity ({0}) cannot be a fraction. To allow this, disable '{2}' in UOM {3}.","Ligne {1}: la quantité ({0}) ne peut pas être une fraction. Pour autoriser cela, désactivez «{2}» dans UdM {3}.",
|
||||||
Must be Whole Number,Doit être un Nombre Entier,
|
Must be Whole Number,Doit être un Nombre Entier,
|
||||||
Please setup Razorpay Plan ID,Veuillez configurer l'ID du plan Razorpay,
|
Please setup Razorpay Plan ID,Veuillez configurer l'ID du plan Razorpay,
|
||||||
@ -4961,7 +4960,7 @@ Threshold for Suggestion,Seuil de suggestion,
|
|||||||
System will notify to increase or decrease quantity or amount ,Le système notifiera d'augmenter ou de diminuer la quantité ou le montant,
|
System will notify to increase or decrease quantity or amount ,Le système notifiera d'augmenter ou de diminuer la quantité ou le montant,
|
||||||
"Higher the number, higher the priority","Plus le nombre est grand, plus la priorité est haute",
|
"Higher the number, higher the priority","Plus le nombre est grand, plus la priorité est haute",
|
||||||
Apply Multiple Pricing Rules,Appliquer plusieurs règles de tarification,
|
Apply Multiple Pricing Rules,Appliquer plusieurs règles de tarification,
|
||||||
Apply Discount on Rate,Appliquer une réduction sur le taux,
|
Apply Discount on Rate,Appliquer une réduction sur le prix,
|
||||||
Validate Applied Rule,Valider la règle appliquée,
|
Validate Applied Rule,Valider la règle appliquée,
|
||||||
Rule Description,Description de la règle,
|
Rule Description,Description de la règle,
|
||||||
Pricing Rule Help,Aide pour les Règles de Tarification,
|
Pricing Rule Help,Aide pour les Règles de Tarification,
|
||||||
@ -5050,19 +5049,18 @@ End date of current invoice's period,Date de fin de la période de facturation e
|
|||||||
Update Auto Repeat Reference,Mettre à jour la référence de répétition automatique,
|
Update Auto Repeat Reference,Mettre à jour la référence de répétition automatique,
|
||||||
Purchase Invoice Advance,Avance sur Facture d’Achat,
|
Purchase Invoice Advance,Avance sur Facture d’Achat,
|
||||||
Purchase Invoice Item,Article de la Facture d'Achat,
|
Purchase Invoice Item,Article de la Facture d'Achat,
|
||||||
Quantity and Rate,Quantité et Taux,
|
Quantity and Rate,Quantité et Prix,
|
||||||
Received Qty,Qté Reçue,
|
Received Qty,Qté Reçue,
|
||||||
Accepted Qty,Quantité acceptée,
|
Accepted Qty,Quantité acceptée,
|
||||||
Rejected Qty,Qté Rejetée,
|
Rejected Qty,Qté Rejetée,
|
||||||
UOM Conversion Factor,Facteur de Conversion de l'UDM,
|
UOM Conversion Factor,Facteur de Conversion de l'UDM,
|
||||||
Discount on Price List Rate (%),Remise sur la Liste des Prix (%),
|
Discount on Price List Rate (%),Remise sur la Liste des Prix (%),
|
||||||
Price List Rate (Company Currency),Taux de la Liste de Prix (Devise Société),
|
Price List Rate (Company Currency),Taux de la Liste de Prix (Devise Société),
|
||||||
Rate ,Taux,
|
|
||||||
Rate (Company Currency),Prix (Devise Société),
|
Rate (Company Currency),Prix (Devise Société),
|
||||||
Amount (Company Currency),Montant (Devise de la Société),
|
Amount (Company Currency),Montant (Devise de la Société),
|
||||||
Is Free Item,Est un article gratuit,
|
Is Free Item,Est un article gratuit,
|
||||||
Net Rate,Taux Net,
|
Net Rate,Prix Net,
|
||||||
Net Rate (Company Currency),Taux Net (Devise Société),
|
Net Rate (Company Currency),Prix Net (Devise Société),
|
||||||
Net Amount (Company Currency),Montant Net (Devise Société),
|
Net Amount (Company Currency),Montant Net (Devise Société),
|
||||||
Item Tax Amount Included in Value,Montant de la taxe incluse dans la valeur,
|
Item Tax Amount Included in Value,Montant de la taxe incluse dans la valeur,
|
||||||
Landed Cost Voucher Amount,Montant de la Référence de Coût au Débarquement,
|
Landed Cost Voucher Amount,Montant de la Référence de Coût au Débarquement,
|
||||||
@ -5080,7 +5078,7 @@ Enable Deferred Expense,Activer les frais reportés,
|
|||||||
Service Start Date,Date de début du service,
|
Service Start Date,Date de début du service,
|
||||||
Service End Date,Date de fin du service,
|
Service End Date,Date de fin du service,
|
||||||
Allow Zero Valuation Rate,Autoriser un Taux de Valorisation Égal à Zéro,
|
Allow Zero Valuation Rate,Autoriser un Taux de Valorisation Égal à Zéro,
|
||||||
Item Tax Rate,Taux de la Taxe sur l'Article,
|
Item Tax Rate,Prix de la Taxe sur l'Article,
|
||||||
Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges,La table de détails de taxe est récupérée depuis les données de base de l'article comme une chaîne de caractères et stockée dans ce champ. Elle est utilisée pour les Taxes et Frais.,
|
Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges,La table de détails de taxe est récupérée depuis les données de base de l'article comme une chaîne de caractères et stockée dans ce champ. Elle est utilisée pour les Taxes et Frais.,
|
||||||
Purchase Order Item,Article de la Commande d'Achat,
|
Purchase Order Item,Article de la Commande d'Achat,
|
||||||
Purchase Receipt Detail,Détail du reçu d'achat,
|
Purchase Receipt Detail,Détail du reçu d'achat,
|
||||||
@ -5098,8 +5096,8 @@ On Previous Row Amount,Le Montant de la Rangée Précédente,
|
|||||||
On Previous Row Total,Le Total de la Rangée Précédente,
|
On Previous Row Total,Le Total de la Rangée Précédente,
|
||||||
On Item Quantity,Sur quantité d'article,
|
On Item Quantity,Sur quantité d'article,
|
||||||
Reference Row #,Ligne de Référence #,
|
Reference Row #,Ligne de Référence #,
|
||||||
Is this Tax included in Basic Rate?,Cette Taxe est-elle incluse dans le Taux de Base ?,
|
Is this Tax included in Basic Rate?,Cette Taxe est-elle incluse dans le Prix de Base ?,
|
||||||
"If checked, the tax amount will be considered as already included in the Print Rate / Print Amount","Si cochée, le montant de la taxe sera considéré comme déjà inclus dans le Taux d'Impression / Prix d'Impression",
|
"If checked, the tax amount will be considered as already included in the Print Rate / Print Amount","Si cochée, le montant de la taxe sera considéré comme déjà inclus dans le Taux / Prix des documents (PDF, impressions)",
|
||||||
Account Head,Compte Principal,
|
Account Head,Compte Principal,
|
||||||
Tax Amount After Discount Amount,Montant de la Taxe après Remise,
|
Tax Amount After Discount Amount,Montant de la Taxe après Remise,
|
||||||
Item Wise Tax Detail ,Détail de la taxe de l'article Wise,
|
Item Wise Tax Detail ,Détail de la taxe de l'article Wise,
|
||||||
@ -5147,7 +5145,7 @@ Accounting Details,Détails Comptabilité,
|
|||||||
Debit To,Débit Pour,
|
Debit To,Débit Pour,
|
||||||
Is Opening Entry,Est Écriture Ouverte,
|
Is Opening Entry,Est Écriture Ouverte,
|
||||||
C-Form Applicable,Formulaire-C Applicable,
|
C-Form Applicable,Formulaire-C Applicable,
|
||||||
Commission Rate (%),Taux de Commission (%),
|
Commission Rate (%),Pourcentage de Commission,
|
||||||
Sales Team1,Équipe des Ventes 1,
|
Sales Team1,Équipe des Ventes 1,
|
||||||
Against Income Account,Pour le Compte de Produits,
|
Against Income Account,Pour le Compte de Produits,
|
||||||
Sales Invoice Advance,Avance sur Facture de Vente,
|
Sales Invoice Advance,Avance sur Facture de Vente,
|
||||||
@ -5157,9 +5155,9 @@ Customer's Item Code,Code de l'Article du Client,
|
|||||||
Brand Name,Nom de la Marque,
|
Brand Name,Nom de la Marque,
|
||||||
Qty as per Stock UOM,Qté par UDM du Stock,
|
Qty as per Stock UOM,Qté par UDM du Stock,
|
||||||
Discount and Margin,Remise et Marge,
|
Discount and Margin,Remise et Marge,
|
||||||
Rate With Margin,Tarif Avec Marge,
|
Rate With Margin,Prix Avec Marge,
|
||||||
Discount (%) on Price List Rate with Margin,Remise (%) sur le Tarif de la Liste de Prix avec la Marge,
|
Discount (%) on Price List Rate with Margin,Remise (%) sur le prix de la Liste de Prix avec la Marge,
|
||||||
Rate With Margin (Company Currency),Taux avec marge (devise de l'entreprise),
|
Rate With Margin (Company Currency),Prix avec marge (devise de l'entreprise),
|
||||||
Delivered By Supplier,Livré par le Fournisseur,
|
Delivered By Supplier,Livré par le Fournisseur,
|
||||||
Deferred Revenue,Produits comptabilisés d'avance,
|
Deferred Revenue,Produits comptabilisés d'avance,
|
||||||
Deferred Revenue Account,Compte de produits comptabilisés d'avance,
|
Deferred Revenue Account,Compte de produits comptabilisés d'avance,
|
||||||
@ -5721,7 +5719,7 @@ 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é,
|
||||||
Opportunity Item,Article de l'Opportunité,
|
Opportunity Item,Article de l'Opportunité,
|
||||||
Basic Rate,Taux de Base,
|
Basic Rate,Prix de Base,
|
||||||
Stage Name,Nom de scène,
|
Stage Name,Nom de scène,
|
||||||
Social Media Post,Publication sur les réseaux sociaux,
|
Social Media Post,Publication sur les réseaux sociaux,
|
||||||
Post Status,Statut du message,
|
Post Status,Statut du message,
|
||||||
@ -7218,8 +7216,8 @@ Qty Consumed Per Unit,Qté Consommée Par Unité,
|
|||||||
Include Item In Manufacturing,Inclure l'article dans la fabrication,
|
Include Item In Manufacturing,Inclure l'article dans la fabrication,
|
||||||
BOM Item,Article de la nomenclature,
|
BOM Item,Article de la nomenclature,
|
||||||
Item operation,Opération de l'article,
|
Item operation,Opération de l'article,
|
||||||
Rate & Amount,Taux et Montant,
|
Rate & Amount,Prix et Montant,
|
||||||
Basic Rate (Company Currency),Taux de Base (Devise de la Société ),
|
Basic Rate (Company Currency),Prix de Base (Devise de la Société ),
|
||||||
Scrap %,% de Rebut,
|
Scrap %,% de Rebut,
|
||||||
Original Item,Article original,
|
Original Item,Article original,
|
||||||
BOM Operation,Opération de la nomenclature (gamme),
|
BOM Operation,Opération de la nomenclature (gamme),
|
||||||
@ -7464,8 +7462,8 @@ Website Attribute,Attribut de site Web,
|
|||||||
Attribute,Attribut,
|
Attribute,Attribut,
|
||||||
Website Filter Field,Champ de filtrage de site Web,
|
Website Filter Field,Champ de filtrage de site Web,
|
||||||
Activity Cost,Coût de l'Activité,
|
Activity Cost,Coût de l'Activité,
|
||||||
Billing Rate,Taux de Facturation,
|
Billing Rate,Prix de Facturation,
|
||||||
Costing Rate,Taux des Coûts,
|
Costing Rate,Tarifs des Coûts,
|
||||||
title,Titre,
|
title,Titre,
|
||||||
Projects User,Utilisateur/Intervenant Projets,
|
Projects User,Utilisateur/Intervenant Projets,
|
||||||
Default Costing Rate,Coût de Revient par Défaut,
|
Default Costing Rate,Coût de Revient par Défaut,
|
||||||
@ -7963,7 +7961,7 @@ Reserved Quantity,Quantité Réservée,
|
|||||||
Actual Quantity,Quantité Réelle,
|
Actual Quantity,Quantité Réelle,
|
||||||
Requested Quantity,Quantité Demandée,
|
Requested Quantity,Quantité Demandée,
|
||||||
Reserved Qty for sub contract,Qté réservée pour le sous-contrat,
|
Reserved Qty for sub contract,Qté réservée pour le sous-contrat,
|
||||||
Moving Average Rate,Taux Mobile Moyen,
|
Moving Average Rate,Prix moyen pondéré,
|
||||||
FCFS Rate,Montant PAPS,
|
FCFS Rate,Montant PAPS,
|
||||||
Customs Tariff Number,Tarifs Personnalisés,
|
Customs Tariff Number,Tarifs Personnalisés,
|
||||||
Tariff Number,Tarif,
|
Tariff Number,Tarif,
|
||||||
@ -8311,7 +8309,7 @@ Total Additional Costs,Total des Coûts Additionnels,
|
|||||||
Customer or Supplier Details,Détails du Client ou du Fournisseur,
|
Customer or Supplier Details,Détails du Client ou du Fournisseur,
|
||||||
Per Transferred,Par transféré,
|
Per Transferred,Par transféré,
|
||||||
Stock Entry Detail,Détails de l'Écriture de Stock,
|
Stock Entry Detail,Détails de l'Écriture de Stock,
|
||||||
Basic Rate (as per Stock UOM),Taux de base (comme l’UDM du Stock),
|
Basic Rate (as per Stock UOM),Prix de base (comme l’UDM du Stock),
|
||||||
Basic Amount,Montant de Base,
|
Basic Amount,Montant de Base,
|
||||||
Additional Cost,Frais Supplémentaire,
|
Additional Cost,Frais Supplémentaire,
|
||||||
Serial No / Batch,N° de Série / Lot,
|
Serial No / Batch,N° de Série / Lot,
|
||||||
@ -8323,7 +8321,7 @@ Stock Entry Child,Entrée de stock enfant,
|
|||||||
PO Supplied Item,PO article fourni,
|
PO Supplied Item,PO article fourni,
|
||||||
Reference Purchase Receipt,Reçu d'achat de référence,
|
Reference Purchase Receipt,Reçu d'achat de référence,
|
||||||
Stock Ledger Entry,Écriture du Livre d'Inventaire,
|
Stock Ledger Entry,Écriture du Livre d'Inventaire,
|
||||||
Outgoing Rate,Taux Sortant,
|
Outgoing Rate,Prix Sortant,
|
||||||
Actual Qty After Transaction,Qté Réelle Après Transaction,
|
Actual Qty After Transaction,Qté Réelle Après Transaction,
|
||||||
Stock Value Difference,Différence de Valeur du Sock,
|
Stock Value Difference,Différence de Valeur du Sock,
|
||||||
Stock Queue (FIFO),File d'Attente du Stock (FIFO),
|
Stock Queue (FIFO),File d'Attente du Stock (FIFO),
|
||||||
@ -8509,7 +8507,7 @@ Item Price Stock,Stock et prix de l'article,
|
|||||||
Item Prices,Prix des Articles,
|
Item Prices,Prix des Articles,
|
||||||
Item Shortage Report,Rapport de Rupture de Stock d'Article,
|
Item Shortage Report,Rapport de Rupture de Stock d'Article,
|
||||||
Item Variant Details,Détails de la variante de l'article,
|
Item Variant Details,Détails de la variante de l'article,
|
||||||
Item-wise Price List Rate,Taux de la Liste des Prix par Article,
|
Item-wise Price List Rate,Prix de la Liste des Prix par Article,
|
||||||
Item-wise Purchase History,Historique d'Achats par Article,
|
Item-wise Purchase History,Historique d'Achats par Article,
|
||||||
Item-wise Purchase Register,Registre des Achats par Article,
|
Item-wise Purchase Register,Registre des Achats par Article,
|
||||||
Item-wise Sales History,Historique des Ventes par Article,
|
Item-wise Sales History,Historique des Ventes par Article,
|
||||||
@ -8561,7 +8559,7 @@ Sales Partner Target Variance based on Item Group,Variance cible du partenaire c
|
|||||||
Sales Partner Transaction Summary,Récapitulatif des transactions du partenaire commercial,
|
Sales Partner Transaction Summary,Récapitulatif des transactions du partenaire commercial,
|
||||||
Sales Partners Commission,Commission des Partenaires de Vente,
|
Sales Partners Commission,Commission des Partenaires de Vente,
|
||||||
Invoiced Amount (Exclusive Tax),Montant facturé (taxe exclusive),
|
Invoiced Amount (Exclusive Tax),Montant facturé (taxe exclusive),
|
||||||
Average Commission Rate,Taux Moyen de la Commission,
|
Average Commission Rate,Coût Moyen de la Commission,
|
||||||
Sales Payment Summary,Résumé du paiement des ventes,
|
Sales Payment Summary,Résumé du paiement des ventes,
|
||||||
Sales Person Commission Summary,Récapitulatif de la commission des ventes,
|
Sales Person Commission Summary,Récapitulatif de la commission des ventes,
|
||||||
Sales Person Target Variance Based On Item Group,Écart cible du commercial basé sur le groupe de postes,
|
Sales Person Target Variance Based On Item Group,Écart cible du commercial basé sur le groupe de postes,
|
||||||
@ -8815,7 +8813,7 @@ Generate New Invoices Past Due Date,Générer de nouvelles factures en retard,
|
|||||||
New invoices will be generated as per schedule even if current invoices are unpaid or past due date,"De nouvelles factures seront générées selon le calendrier, même si les factures actuelles sont impayées ou en retard",
|
New invoices will be generated as per schedule even if current invoices are unpaid or past due date,"De nouvelles factures seront générées selon le calendrier, même si les factures actuelles sont impayées ou en retard",
|
||||||
Document Type ,Type de document,
|
Document Type ,Type de document,
|
||||||
Subscription Price Based On,Prix d'abonnement basé sur,
|
Subscription Price Based On,Prix d'abonnement basé sur,
|
||||||
Fixed Rate,Taux fixe,
|
Fixed Rate,Tarif fixe,
|
||||||
Based On Price List,Basé sur la liste de prix,
|
Based On Price List,Basé sur la liste de prix,
|
||||||
Monthly Rate,Tarif mensuel,
|
Monthly Rate,Tarif mensuel,
|
||||||
Cancel Subscription After Grace Period,Annuler l'abonnement après la période de grâce,
|
Cancel Subscription After Grace Period,Annuler l'abonnement après la période de grâce,
|
||||||
@ -8886,10 +8884,6 @@ Practitioner Name,Nom du praticien,
|
|||||||
Enter a name for the Clinical Procedure Template,Entrez un nom pour le modèle de procédure clinique,
|
Enter a name for the Clinical Procedure Template,Entrez un nom pour le modèle de procédure clinique,
|
||||||
Set the Item Code which will be used for billing the Clinical Procedure.,Définissez le code article qui sera utilisé pour facturer la procédure clinique.,
|
Set the Item Code which will be used for billing the Clinical Procedure.,Définissez le code article qui sera utilisé pour facturer la procédure clinique.,
|
||||||
Select an Item Group for the Clinical Procedure Item.,Sélectionnez un groupe d'articles pour l'article de procédure clinique.,
|
Select an Item Group for the Clinical Procedure Item.,Sélectionnez un groupe d'articles pour l'article de procédure clinique.,
|
||||||
Clinical Procedure Rate,Taux de procédure clinique,
|
|
||||||
Check this if the Clinical Procedure is billable and also set the rate.,Cochez cette case si la procédure clinique est facturable et définissez également le tarif.,
|
|
||||||
Check this if the Clinical Procedure utilises consumables. Click ,Vérifiez ceci si la procédure clinique utilise des consommables. Cliquez sur,
|
|
||||||
to know more,en savoir plus,
|
|
||||||
"You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.","Vous pouvez également définir le service médical du modèle. Après avoir enregistré le document, un élément sera automatiquement créé pour facturer cette procédure clinique. Vous pouvez ensuite utiliser ce modèle lors de la création de procédures cliniques pour les patients. Les modèles vous évitent de remplir des données redondantes à chaque fois. Vous pouvez également créer des modèles pour d'autres opérations telles que des tests de laboratoire, des séances de thérapie, etc.",
|
"You can also set the Medical Department for the template. After saving the document, an Item will automatically be created for billing this Clinical Procedure. You can then use this template while creating Clinical Procedures for Patients. Templates save you from filling up redundant data every single time. You can also create templates for other operations like Lab Tests, Therapy Sessions, etc.","Vous pouvez également définir le service médical du modèle. Après avoir enregistré le document, un élément sera automatiquement créé pour facturer cette procédure clinique. Vous pouvez ensuite utiliser ce modèle lors de la création de procédures cliniques pour les patients. Les modèles vous évitent de remplir des données redondantes à chaque fois. Vous pouvez également créer des modèles pour d'autres opérations telles que des tests de laboratoire, des séances de thérapie, etc.",
|
||||||
Descriptive Test Result,Résultat du test descriptif,
|
Descriptive Test Result,Résultat du test descriptif,
|
||||||
Allow Blank,Autoriser le blanc,
|
Allow Blank,Autoriser le blanc,
|
||||||
@ -9033,7 +9027,7 @@ Work In Progress Warehouse,Entrepôt de travaux en cours,
|
|||||||
This Warehouse will be auto-updated in the Work In Progress Warehouse field of Work Orders.,Cet entrepôt sera mis à jour automatiquement dans le champ Entrepôt de travaux en cours des bons de travail.,
|
This Warehouse will be auto-updated in the Work In Progress Warehouse field of Work Orders.,Cet entrepôt sera mis à jour automatiquement dans le champ Entrepôt de travaux en cours des bons de travail.,
|
||||||
Finished Goods Warehouse,Entrepôt de produits finis,
|
Finished Goods Warehouse,Entrepôt de produits finis,
|
||||||
This Warehouse will be auto-updated in the Target Warehouse field of Work Order.,Cet entrepôt sera mis à jour automatiquement dans le champ Entrepôt cible de l'ordre de fabrication.
|
This Warehouse will be auto-updated in the Target Warehouse field of Work Order.,Cet entrepôt sera mis à jour automatiquement dans le champ Entrepôt cible de l'ordre de fabrication.
|
||||||
"If ticked, the BOM cost will be automatically updated based on Valuation Rate / Price List Rate / last purchase rate of raw materials.","Si coché, le coût de la nomenclature sera automatiquement mis à jour en fonction du taux de valorisation / tarif tarifaire / dernier taux d'achat des matières premières.",
|
"If ticked, the BOM cost will be automatically updated based on Valuation Rate / Price List Rate / last purchase rate of raw materials.","Si coché, le coût de la nomenclature sera automatiquement mis à jour en fonction du taux de valorisation / prix de la liste prix / dernier prix d'achat des matières premières.",
|
||||||
Source Warehouses (Optional),Entrepôts d'origine (facultatif),
|
Source Warehouses (Optional),Entrepôts d'origine (facultatif),
|
||||||
"System will pickup the materials from the selected warehouses. If not specified, system will create material request for purchase.","Le système ramassera les matériaux dans les entrepôts sélectionnés. S'il n'est pas spécifié, le système créera une demande de matériel pour l'achat.",
|
"System will pickup the materials from the selected warehouses. If not specified, system will create material request for purchase.","Le système ramassera les matériaux dans les entrepôts sélectionnés. S'il n'est pas spécifié, le système créera une demande de matériel pour l'achat.",
|
||||||
Lead Time,Délai de mise en œuvre,
|
Lead Time,Délai de mise en œuvre,
|
||||||
@ -9107,7 +9101,7 @@ MAT-PR-RET-.YYYY.-,MAT-PR-RET-.YYYY.-,
|
|||||||
Track this Purchase Receipt against any Project,Suivre ce reçu d'achat par rapport à n'importe quel projet,
|
Track this Purchase Receipt against any Project,Suivre ce reçu d'achat par rapport à n'importe quel projet,
|
||||||
Please Select a Supplier,Veuillez sélectionner un fournisseur,
|
Please Select a Supplier,Veuillez sélectionner un fournisseur,
|
||||||
Add to Transit,Ajouter à Transit,
|
Add to Transit,Ajouter à Transit,
|
||||||
Set Basic Rate Manually,Définir manuellement le taux de base,
|
Set Basic Rate Manually,Définir manuellement le prix de base,
|
||||||
"By default, the Item Name is set as per the Item Code entered. If you want Items to be named by a ","Par défaut, le nom de l'article est défini selon le code d'article entré. Si vous souhaitez que les éléments soient nommés par un",
|
"By default, the Item Name is set as per the Item Code entered. If you want Items to be named by a ","Par défaut, le nom de l'article est défini selon le code d'article entré. Si vous souhaitez que les éléments soient nommés par un",
|
||||||
Set a Default Warehouse for Inventory Transactions. This will be fetched into the Default Warehouse in the Item master.,Définissez un entrepôt par défaut pour les mouvements de stock. Ce sera récupéré dans l'entrepôt par défaut dans la base d'articles.,
|
Set a Default Warehouse for Inventory Transactions. This will be fetched into the Default Warehouse in the Item master.,Définissez un entrepôt par défaut pour les mouvements de stock. Ce sera récupéré dans l'entrepôt par défaut dans la base d'articles.,
|
||||||
"This will allow stock items to be displayed in negative values. Using this option depends on your use case. With this option unchecked, the system warns before obstructing a transaction that is causing negative stock.","Cela permettra aux articles en stock d'être affichés avec des valeurs négatives. L'utilisation de cette option dépend de votre cas d'utilisation. Lorsque cette option n'est pas cochée, le système avertit avant d'entraver une transaction entraînant un stock négatif.",
|
"This will allow stock items to be displayed in negative values. Using this option depends on your use case. With this option unchecked, the system warns before obstructing a transaction that is causing negative stock.","Cela permettra aux articles en stock d'être affichés avec des valeurs négatives. L'utilisation de cette option dépend de votre cas d'utilisation. Lorsque cette option n'est pas cochée, le système avertit avant d'entraver une transaction entraînant un stock négatif.",
|
||||||
@ -9495,7 +9489,7 @@ Normal Range: ,Plage normale:,
|
|||||||
Row #{0}: Check Out datetime cannot be less than Check In datetime,Ligne n ° {0}: la date de sortie ne peut pas être inférieure à la date de sortie,
|
Row #{0}: Check Out datetime cannot be less than Check In datetime,Ligne n ° {0}: la date de sortie ne peut pas être inférieure à la date de sortie,
|
||||||
"Missing required details, did not create Inpatient Record","Détails requis manquants, n'a pas créé de dossier d'hospitalisation",
|
"Missing required details, did not create Inpatient Record","Détails requis manquants, n'a pas créé de dossier d'hospitalisation",
|
||||||
Unbilled Invoices,Factures non facturées,
|
Unbilled Invoices,Factures non facturées,
|
||||||
Standard Selling Rate should be greater than zero.,Le taux de vente standard doit être supérieur à zéro.,
|
Standard Selling Rate should be greater than zero.,Le prix de vente standard doit être supérieur à zéro.,
|
||||||
Conversion Factor is mandatory,Le facteur de conversion est obligatoire,
|
Conversion Factor is mandatory,Le facteur de conversion est obligatoire,
|
||||||
Row #{0}: Conversion Factor is mandatory,Ligne n ° {0}: le facteur de conversion est obligatoire,
|
Row #{0}: Conversion Factor is mandatory,Ligne n ° {0}: le facteur de conversion est obligatoire,
|
||||||
Sample Quantity cannot be negative or 0,La quantité d'échantillon ne peut pas être négative ou 0,
|
Sample Quantity cannot be negative or 0,La quantité d'échantillon ne peut pas être négative ou 0,
|
||||||
@ -9559,7 +9553,7 @@ The Request for Quotation can be accessed by clicking on the following button,La
|
|||||||
Regards,Cordialement,
|
Regards,Cordialement,
|
||||||
Please click on the following button to set your new password,Veuillez cliquer sur le bouton suivant pour définir votre nouveau mot de passe,
|
Please click on the following button to set your new password,Veuillez cliquer sur le bouton suivant pour définir votre nouveau mot de passe,
|
||||||
Update Password,Mettre à jour le mot de passe,
|
Update Password,Mettre à jour le mot de passe,
|
||||||
Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ligne n ° {}: le taux de vente de l'article {} est inférieur à son {}. La vente {} doit être au moins {},
|
Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {},Ligne n ° {}: le prix de vente de l'article {} est inférieur à son {}. La vente {} doit être au moins {},
|
||||||
You can alternatively disable selling price validation in {} to bypass this validation.,Vous pouvez également désactiver la validation du prix de vente dans {} pour contourner cette validation.,
|
You can alternatively disable selling price validation in {} to bypass this validation.,Vous pouvez également désactiver la validation du prix de vente dans {} pour contourner cette validation.,
|
||||||
Invalid Selling Price,Prix de vente invalide,
|
Invalid Selling Price,Prix de vente invalide,
|
||||||
Address needs to be linked to a Company. Please add a row for Company in the Links table.,L'adresse doit être liée à une entreprise. Veuillez ajouter une ligne pour Entreprise dans le tableau Liens.,
|
Address needs to be linked to a Company. Please add a row for Company in the Links table.,L'adresse doit être liée à une entreprise. Veuillez ajouter une ligne pour Entreprise dans le tableau Liens.,
|
||||||
@ -9581,7 +9575,7 @@ Only select this if you have set up the Cash Flow Mapper documents,Sélectionnez
|
|||||||
Payment Channel,Canal de paiement,
|
Payment Channel,Canal de paiement,
|
||||||
Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Une Commande d'Achat est-il requis pour la création de factures d'achat et de reçus?,
|
Is Purchase Order Required for Purchase Invoice & Receipt Creation?,Une Commande d'Achat est-il requis pour la création de factures d'achat et de reçus?,
|
||||||
Is Purchase Receipt Required for Purchase Invoice Creation?,Un reçu d'achat est-il requis pour la création d'une facture d'achat?,
|
Is Purchase Receipt Required for Purchase Invoice Creation?,Un reçu d'achat est-il requis pour la création d'une facture d'achat?,
|
||||||
Maintain Same Rate Throughout the Purchase Cycle,Maintenir le même taux tout au long du cycle d'achat,
|
Maintain Same Rate Throughout the Purchase Cycle,Maintenir les même prix tout au long du cycle d'achat,
|
||||||
Allow Item To Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
|
Allow Item To Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
|
||||||
Suppliers,Fournisseurs,
|
Suppliers,Fournisseurs,
|
||||||
Send Emails to Suppliers,Envoyer des e-mails aux fournisseurs,
|
Send Emails to Suppliers,Envoyer des e-mails aux fournisseurs,
|
||||||
@ -9633,7 +9627,7 @@ Plan operations X days in advance,Planifier les opérations X jours à l'avance,
|
|||||||
Time Between Operations (Mins),Temps entre les opérations (minutes),
|
Time Between Operations (Mins),Temps entre les opérations (minutes),
|
||||||
Default: 10 mins,Par défaut: 10 minutes,
|
Default: 10 mins,Par défaut: 10 minutes,
|
||||||
Overproduction for Sales and Work Order,Surproduction pour les ventes et les bons de travail,
|
Overproduction for Sales and Work Order,Surproduction pour les ventes et les bons de travail,
|
||||||
"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Mettre à jour automatiquement le coût de la nomenclature via le planificateur, en fonction du dernier taux de valorisation / tarif tarifaire / dernier taux d'achat de matières premières",
|
"Update BOM cost automatically via scheduler, based on the latest Valuation Rate/Price List Rate/Last Purchase Rate of raw materials","Mettre à jour automatiquement le coût de la nomenclature via le planificateur, en fonction du dernier taux de valorisation / prix de la liste de prix / dernier prix d'achat de matières premières",
|
||||||
Purchase Order already created for all Sales Order items,Commande d'Achat déjà créé pour tous les articles de commande client,
|
Purchase Order already created for all Sales Order items,Commande d'Achat déjà créé pour tous les articles de commande client,
|
||||||
Select Items,Sélectionner des éléments,
|
Select Items,Sélectionner des éléments,
|
||||||
Against Default Supplier,Contre le fournisseur par défaut,
|
Against Default Supplier,Contre le fournisseur par défaut,
|
||||||
@ -9641,14 +9635,14 @@ Auto close Opportunity after the no. of days mentioned above,Opportunité de fer
|
|||||||
Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Une commande client est-elle requise pour la création de factures clients et de bons de livraison?,
|
Is Sales Order Required for Sales Invoice & Delivery Note Creation?,Une commande client est-elle requise pour la création de factures clients et de bons de livraison?,
|
||||||
Is Delivery Note Required for Sales Invoice Creation?,Un bon de livraison est-il nécessaire pour la création de factures de vente?,
|
Is Delivery Note Required for Sales Invoice Creation?,Un bon de livraison est-il nécessaire pour la création de factures de vente?,
|
||||||
How often should Project and Company be updated based on Sales Transactions?,À quelle fréquence le projet et l'entreprise doivent-ils être mis à jour en fonction des transactions de vente?,
|
How often should Project and Company be updated based on Sales Transactions?,À quelle fréquence le projet et l'entreprise doivent-ils être mis à jour en fonction des transactions de vente?,
|
||||||
Allow User to Edit Price List Rate in Transactions,Autoriser l'utilisateur à modifier le tarif tarifaire dans les transactions,
|
Allow User to Edit Price List Rate in Transactions,Autoriser l'utilisateur à modifier le prix de la liste prix dans les transactions,
|
||||||
Allow Item to Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
|
Allow Item to Be Added Multiple Times in a Transaction,Autoriser l'ajout d'un article plusieurs fois dans une transaction,
|
||||||
Allow Multiple Sales Orders Against a Customer's Purchase Order,Autoriser plusieurs commandes client par rapport à la commande d'achat d'un client,
|
Allow Multiple Sales Orders Against a Customer's Purchase Order,Autoriser plusieurs commandes client par rapport à la commande d'achat d'un client,
|
||||||
Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valider le prix de vente de l'article par rapport au taux d'achat ou au taux de valorisation,
|
Validate Selling Price for Item Against Purchase Rate or Valuation Rate,Valider le prix de vente de l'article par rapport au prix d'achat ou au taux de valorisation,
|
||||||
Hide Customer's Tax ID from Sales Transactions,Masquer le numéro d'identification fiscale du client dans les transactions de vente,
|
Hide Customer's Tax ID from Sales Transactions,Masquer le numéro d'identification fiscale du client dans les transactions de vente,
|
||||||
"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Le pourcentage que vous êtes autorisé à recevoir ou à livrer plus par rapport à la quantité commandée. Par exemple, si vous avez commandé 100 unités et que votre allocation est de 10%, vous êtes autorisé à recevoir 110 unités.",
|
"The percentage you are allowed to receive or deliver more against the quantity ordered. For example, if you have ordered 100 units, and your Allowance is 10%, then you are allowed to receive 110 units.","Le pourcentage que vous êtes autorisé à recevoir ou à livrer plus par rapport à la quantité commandée. Par exemple, si vous avez commandé 100 unités et que votre allocation est de 10%, vous êtes autorisé à recevoir 110 unités.",
|
||||||
Action If Quality Inspection Is Not Submitted,Action si l'inspection qualité n'est pas soumise,
|
Action If Quality Inspection Is Not Submitted,Action si l'inspection qualité n'est pas soumise,
|
||||||
Auto Insert Price List Rate If Missing,Taux de liste de prix d'insertion automatique s'il est manquant,
|
Auto Insert Price List Rate If Missing,Insérer automatiquement le prix dand liste de prix s'il est manquant,
|
||||||
Automatically Set Serial Nos Based on FIFO,Définir automatiquement les numéros de série en fonction de FIFO,
|
Automatically Set Serial Nos Based on FIFO,Définir automatiquement les numéros de série en fonction de FIFO,
|
||||||
Set Qty in Transactions Based on Serial No Input,Définir la quantité dans les transactions en fonction du numéro de série,
|
Set Qty in Transactions Based on Serial No Input,Définir la quantité dans les transactions en fonction du numéro de série,
|
||||||
Raise Material Request When Stock Reaches Re-order Level,Augmenter la demande d'article lorsque le stock atteint le niveau de commande,
|
Raise Material Request When Stock Reaches Re-order Level,Augmenter la demande d'article lorsque le stock atteint le niveau de commande,
|
||||||
@ -9722,7 +9716,7 @@ No Inpatient Record found against patient {0},Aucun dossier d'hospitalisation tr
|
|||||||
An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Une ordonnance de médicament pour patients hospitalisés {0} contre rencontre avec un patient {1} existe déjà.,
|
An Inpatient Medication Order {0} against Patient Encounter {1} already exists.,Une ordonnance de médicament pour patients hospitalisés {0} contre rencontre avec un patient {1} existe déjà.,
|
||||||
Allow In Returns,Autoriser les retours,
|
Allow In Returns,Autoriser les retours,
|
||||||
Hide Unavailable Items,Masquer les éléments non disponibles,
|
Hide Unavailable Items,Masquer les éléments non disponibles,
|
||||||
Apply Discount on Discounted Rate,Appliquer une remise sur un tarif réduit,
|
Apply Discount on Discounted Rate,Appliquer une remise sur un prix réduit,
|
||||||
Therapy Plan Template,Modèle de plan de thérapie,
|
Therapy Plan Template,Modèle de plan de thérapie,
|
||||||
Fetching Template Details,Récupération des détails du modèle,
|
Fetching Template Details,Récupération des détails du modèle,
|
||||||
Linked Item Details,Détails de l'élément lié,
|
Linked Item Details,Détails de l'élément lié,
|
||||||
@ -9927,4 +9921,3 @@ Enable Reviews and Ratings,Activer les avis et notes
|
|||||||
Enable Recommendations,Activer les recommendations
|
Enable Recommendations,Activer les recommendations
|
||||||
Item Search Settings,Paramétrage de la recherche d'article
|
Item Search Settings,Paramétrage de la recherche d'article
|
||||||
Purchase demande,Demande de materiel
|
Purchase demande,Demande de materiel
|
||||||
Calendar,Calendier
|
|
||||||
|
Can't render this file because it is too large.
|
@ -71,6 +71,9 @@ class TransactionBase(StatusUpdater):
|
|||||||
self.validate_value(field, condition, prevdoc_values[field], doc)
|
self.validate_value(field, condition, prevdoc_values[field], doc)
|
||||||
|
|
||||||
def validate_rate_with_reference_doc(self, ref_details):
|
def validate_rate_with_reference_doc(self, ref_details):
|
||||||
|
if self.get("is_internal_supplier"):
|
||||||
|
return
|
||||||
|
|
||||||
buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
|
buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
|
||||||
|
|
||||||
if self.doctype in buying_doctypes:
|
if self.doctype in buying_doctypes:
|
||||||
|
@ -12,7 +12,6 @@ dependencies = [
|
|||||||
"pycountry~=20.7.3",
|
"pycountry~=20.7.3",
|
||||||
"python-stdnum~=1.16",
|
"python-stdnum~=1.16",
|
||||||
"Unidecode~=1.2.0",
|
"Unidecode~=1.2.0",
|
||||||
"redisearch~=2.1.0",
|
|
||||||
|
|
||||||
# integration dependencies
|
# integration dependencies
|
||||||
"gocardless-pro~=1.22.0",
|
"gocardless-pro~=1.22.0",
|
||||||
@ -21,6 +20,9 @@ dependencies = [
|
|||||||
"python-youtube~=0.8.0",
|
"python-youtube~=0.8.0",
|
||||||
"taxjar~=1.9.2",
|
"taxjar~=1.9.2",
|
||||||
"tweepy~=3.10.0",
|
"tweepy~=3.10.0",
|
||||||
|
|
||||||
|
# Not used directly - required by PyQRCode for PNG generation
|
||||||
|
"pypng~=0.20220715.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user