Merge branch 'develop' into provision-to-return-components
This commit is contained in:
commit
73a9791401
@ -99,7 +99,7 @@ class BankClearance(Document):
|
||||
.where(loan_disbursement.clearance_date.isnull())
|
||||
.where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account]))
|
||||
.orderby(loan_disbursement.disbursement_date)
|
||||
.orderby(loan_disbursement.name, frappe.qb.desc)
|
||||
.orderby(loan_disbursement.name, order=frappe.qb.desc)
|
||||
).run(as_dict=1)
|
||||
|
||||
loan_repayment = frappe.qb.DocType("Loan Repayment")
|
||||
@ -126,7 +126,9 @@ class BankClearance(Document):
|
||||
if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
|
||||
query = query.where((loan_repayment.repay_from_salary == 0))
|
||||
|
||||
query = query.orderby(loan_repayment.posting_date).orderby(loan_repayment.name, frappe.qb.desc)
|
||||
query = query.orderby(loan_repayment.posting_date).orderby(
|
||||
loan_repayment.name, order=frappe.qb.desc
|
||||
)
|
||||
|
||||
loan_repayments = query.run(as_dict=True)
|
||||
|
||||
|
@ -173,8 +173,8 @@ frappe.ui.form.on("Journal Entry", {
|
||||
var update_jv_details = function(doc, r) {
|
||||
$.each(r, function(i, d) {
|
||||
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
|
||||
row.account = d.account;
|
||||
row.balance = d.balance;
|
||||
frappe.model.set_value(row.doctype, row.name, "account", d.account)
|
||||
frappe.model.set_value(row.doctype, row.name, "balance", d.balance)
|
||||
});
|
||||
refresh_field("accounts");
|
||||
}
|
||||
|
@ -186,8 +186,10 @@
|
||||
{
|
||||
"fetch_from": "bank_account.bank",
|
||||
"fieldname": "bank",
|
||||
"fieldtype": "Read Only",
|
||||
"label": "Bank"
|
||||
"fieldtype": "Link",
|
||||
"label": "Bank",
|
||||
"options": "Bank",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "bank_account.bank_account_no",
|
||||
@ -366,10 +368,11 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-18 12:24:14.178853",
|
||||
"modified": "2022-09-30 16:19:43.680025",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Request",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@ -401,5 +404,6 @@
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
@ -343,7 +343,8 @@
|
||||
"no_copy": 1,
|
||||
"options": "POS Invoice",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@ -1553,7 +1554,7 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-03-22 13:00:24.166684",
|
||||
"modified": "2022-09-30 03:49:50.455199",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Invoice",
|
||||
|
@ -239,14 +239,14 @@ class POSInvoice(SalesInvoice):
|
||||
frappe.bold(d.warehouse),
|
||||
frappe.bold(d.qty),
|
||||
)
|
||||
if flt(available_stock) <= 0:
|
||||
if is_stock_item and flt(available_stock) <= 0:
|
||||
frappe.throw(
|
||||
_("Row #{}: Item Code: {} is not available under warehouse {}.").format(
|
||||
d.idx, item_code, warehouse
|
||||
),
|
||||
title=_("Item Unavailable"),
|
||||
)
|
||||
elif flt(available_stock) < flt(d.qty):
|
||||
elif is_stock_item and flt(available_stock) < flt(d.qty):
|
||||
frappe.throw(
|
||||
_(
|
||||
"Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}."
|
||||
@ -632,11 +632,12 @@ def get_stock_availability(item_code, warehouse):
|
||||
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
|
||||
return bin_qty - pos_sales_qty, is_stock_item
|
||||
else:
|
||||
is_stock_item = False
|
||||
is_stock_item = True
|
||||
if frappe.db.exists("Product Bundle", item_code):
|
||||
return get_bundle_availability(item_code, warehouse), is_stock_item
|
||||
else:
|
||||
# Is a service item
|
||||
is_stock_item = False
|
||||
# Is a service item or non_stock item
|
||||
return 0, is_stock_item
|
||||
|
||||
|
||||
@ -650,7 +651,9 @@ def get_bundle_availability(bundle_item_code, warehouse):
|
||||
available_qty = item_bin_qty - item_pos_reserved_qty
|
||||
|
||||
max_available_bundles = available_qty / item.qty
|
||||
if bundle_bin_qty > max_available_bundles:
|
||||
if bundle_bin_qty > max_available_bundles and frappe.get_value(
|
||||
"Item", item.item_code, "is_stock_item"
|
||||
):
|
||||
bundle_bin_qty = max_available_bundles
|
||||
|
||||
pos_sales_qty = get_pos_reserved_qty(bundle_item_code, warehouse)
|
||||
|
@ -98,7 +98,6 @@
|
||||
"section_break_44",
|
||||
"apply_discount_on",
|
||||
"base_discount_amount",
|
||||
"additional_discount_account",
|
||||
"column_break_46",
|
||||
"additional_discount_percentage",
|
||||
"discount_amount",
|
||||
@ -1387,12 +1386,6 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "additional_discount_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Additional Discount Account",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "ignore_default_payment_terms_template",
|
||||
@ -1437,6 +1430,7 @@
|
||||
"fieldname": "tax_withheld_vouchers",
|
||||
"fieldtype": "Table",
|
||||
"label": "Tax Withheld Vouchers",
|
||||
"no_copy": 1,
|
||||
"options": "Tax Withheld Vouchers",
|
||||
"read_only": 1
|
||||
}
|
||||
@ -1445,7 +1439,7 @@
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-09-13 23:39:54.525037",
|
||||
"modified": "2022-10-07 14:19:14.214157",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -669,9 +669,6 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
exchange_rate_map, net_rate_map = get_purchase_document_details(self)
|
||||
|
||||
enable_discount_accounting = cint(
|
||||
frappe.db.get_single_value("Buying Settings", "enable_discount_accounting")
|
||||
)
|
||||
provisional_accounting_for_non_stock_items = cint(
|
||||
frappe.db.get_value(
|
||||
"Company", self.company, "enable_provisional_accounting_for_non_stock_items"
|
||||
@ -1159,9 +1156,6 @@ class PurchaseInvoice(BuyingController):
|
||||
def make_tax_gl_entries(self, gl_entries):
|
||||
# tax table gl entries
|
||||
valuation_tax = {}
|
||||
enable_discount_accounting = cint(
|
||||
frappe.db.get_single_value("Buying Settings", "enable_discount_accounting")
|
||||
)
|
||||
|
||||
for tax in self.get("taxes"):
|
||||
amount, base_amount = self.get_tax_amounts(tax, None)
|
||||
@ -1249,15 +1243,6 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
def enable_discount_accounting(self):
|
||||
if not hasattr(self, "_enable_discount_accounting"):
|
||||
self._enable_discount_accounting = cint(
|
||||
frappe.db.get_single_value("Buying Settings", "enable_discount_accounting")
|
||||
)
|
||||
|
||||
return self._enable_discount_accounting
|
||||
|
||||
def make_internal_transfer_gl_entries(self, gl_entries):
|
||||
if self.is_internal_transfer() and flt(self.base_total_taxes_and_charges):
|
||||
account_currency = get_account_currency(self.unrealized_profit_loss_account)
|
||||
|
@ -74,7 +74,6 @@
|
||||
"manufacturer_part_no",
|
||||
"accounting",
|
||||
"expense_account",
|
||||
"discount_account",
|
||||
"col_break5",
|
||||
"is_fixed_asset",
|
||||
"asset_location",
|
||||
@ -860,12 +859,6 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "discount_account",
|
||||
"fieldtype": "Link",
|
||||
"label": "Discount Account",
|
||||
"options": "Account"
|
||||
},
|
||||
{
|
||||
"fieldname": "product_bundle",
|
||||
"fieldtype": "Link",
|
||||
@ -877,7 +870,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2022-06-17 05:31:10.520171",
|
||||
"modified": "2022-09-27 10:54:23.980713",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
|
@ -22,9 +22,12 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente
|
||||
from erpnext.accounts.party import get_due_date, get_party_account, get_party_details
|
||||
from erpnext.accounts.utils import get_account_currency
|
||||
from erpnext.assets.doctype.asset.depreciation import (
|
||||
depreciate_asset,
|
||||
get_disposal_account_and_cost_center,
|
||||
get_gl_entries_on_asset_disposal,
|
||||
get_gl_entries_on_asset_regain,
|
||||
reset_depreciation_schedule,
|
||||
reverse_depreciation_entry_made_after_disposal,
|
||||
)
|
||||
from erpnext.controllers.accounts_controller import validate_account_head
|
||||
from erpnext.controllers.selling_controller import SellingController
|
||||
@ -1086,18 +1089,20 @@ class SalesInvoice(SellingController):
|
||||
asset.db_set("disposal_date", None)
|
||||
|
||||
if asset.calculate_depreciation:
|
||||
self.reverse_depreciation_entry_made_after_disposal(asset)
|
||||
self.reset_depreciation_schedule(asset)
|
||||
posting_date = frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
|
||||
reverse_depreciation_entry_made_after_disposal(asset, posting_date)
|
||||
reset_depreciation_schedule(asset, self.posting_date)
|
||||
|
||||
else:
|
||||
if asset.calculate_depreciation:
|
||||
depreciate_asset(asset, self.posting_date)
|
||||
asset.reload()
|
||||
|
||||
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
|
||||
asset, item.base_net_amount, item.finance_book, self.get("doctype"), self.get("name")
|
||||
)
|
||||
asset.db_set("disposal_date", self.posting_date)
|
||||
|
||||
if asset.calculate_depreciation:
|
||||
self.depreciate_asset(asset)
|
||||
|
||||
for gle in fixed_asset_gl_entries:
|
||||
gle["against"] = self.customer
|
||||
gl_entries.append(self.get_gl_dict(gle, item=item))
|
||||
|
@ -8,7 +8,7 @@ import frappe
|
||||
from frappe.model.dynamic_links import get_dynamic_link_map
|
||||
from frappe.model.naming import make_autoname
|
||||
from frappe.tests.utils import change_settings
|
||||
from frappe.utils import add_days, flt, getdate, nowdate
|
||||
from frappe.utils import add_days, flt, getdate, nowdate, today
|
||||
|
||||
import erpnext
|
||||
from erpnext.accounts.doctype.account.test_account import create_account, get_inventory_account
|
||||
@ -3196,6 +3196,37 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
"Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice", unlink_enabled
|
||||
)
|
||||
|
||||
def test_batch_expiry_for_sales_invoice_return(self):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
|
||||
item = make_item(
|
||||
"_Test Batch Item For Return Check",
|
||||
{
|
||||
"is_purchase_item": 1,
|
||||
"is_stock_item": 1,
|
||||
"has_batch_no": 1,
|
||||
"create_new_batch": 1,
|
||||
"batch_number_series": "TBIRC.#####",
|
||||
},
|
||||
)
|
||||
|
||||
pr = make_purchase_receipt(qty=1, item_code=item.name)
|
||||
|
||||
batch_no = pr.items[0].batch_no
|
||||
si = create_sales_invoice(qty=1, item_code=item.name, update_stock=1, batch_no=batch_no)
|
||||
|
||||
si.load_from_db()
|
||||
batch_no = si.items[0].batch_no
|
||||
self.assertTrue(batch_no)
|
||||
|
||||
frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1))
|
||||
|
||||
return_si = make_return_doc(si.doctype, si.name)
|
||||
return_si.save().submit()
|
||||
|
||||
self.assertTrue(return_si.docstatus == 1)
|
||||
|
||||
|
||||
def get_sales_invoice_for_e_invoice():
|
||||
si = make_sales_invoice_for_ewaybill()
|
||||
@ -3289,6 +3320,7 @@ def create_sales_invoice(**args):
|
||||
"serial_no": args.serial_no,
|
||||
"conversion_factor": 1,
|
||||
"incoming_rate": args.incoming_rate or 0,
|
||||
"batch_no": args.batch_no or None,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -249,6 +249,9 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
|
||||
)
|
||||
else:
|
||||
tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
|
||||
|
||||
# once tds is deducted, not need to add vouchers in the invoice
|
||||
voucher_wise_amount = {}
|
||||
else:
|
||||
tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers)
|
||||
|
||||
@ -335,6 +338,9 @@ def get_advance_vouchers(
|
||||
"party": ["in", parties],
|
||||
}
|
||||
|
||||
if party_type == "Customer":
|
||||
filters.update({"against_voucher": ["is", "not set"]})
|
||||
|
||||
if company:
|
||||
filters["company"] = company
|
||||
if from_date and to_date:
|
||||
@ -422,7 +428,10 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
|
||||
):
|
||||
# Get net total again as TDS is calculated on net total
|
||||
# Grand is used to just check for threshold breach
|
||||
net_total = frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(net_total)") or 0.0
|
||||
net_total = 0
|
||||
if vouchers:
|
||||
net_total = frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(net_total)")
|
||||
|
||||
net_total += inv.net_total
|
||||
supp_credit_amt = net_total - cumulative_threshold
|
||||
|
||||
|
@ -370,7 +370,7 @@ def get_conditions(filters):
|
||||
where parent=`tabSales Invoice`.name
|
||||
and ifnull(`tab{table}`.{field}, '') = %({field})s)"""
|
||||
|
||||
conditions += get_sales_invoice_item_field_condition("mode_of_payments", "Sales Invoice Payment")
|
||||
conditions += get_sales_invoice_item_field_condition("mode_of_payment", "Sales Invoice Payment")
|
||||
conditions += get_sales_invoice_item_field_condition("cost_center")
|
||||
conditions += get_sales_invoice_item_field_condition("warehouse")
|
||||
conditions += get_sales_invoice_item_field_condition("brand")
|
||||
|
@ -86,7 +86,7 @@ def get_fiscal_years(
|
||||
)
|
||||
)
|
||||
|
||||
query = query.orderby(FY.year_start_date, Order.desc)
|
||||
query = query.orderby(FY.year_start_date, order=Order.desc)
|
||||
fiscal_years = query.run(as_dict=True)
|
||||
|
||||
frappe.cache().hset("fiscal_years", company, fiscal_years)
|
||||
|
@ -388,7 +388,7 @@
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt",
|
||||
"options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt\nCapitalized\nDecapitalized",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
|
@ -828,7 +828,9 @@ class Asset(AccountsController):
|
||||
|
||||
|
||||
def update_maintenance_status():
|
||||
assets = frappe.get_all("Asset", filters={"docstatus": 1, "maintenance_required": 1})
|
||||
assets = frappe.get_all(
|
||||
"Asset", filters={"docstatus": 1, "maintenance_required": 1, "disposal_date": ("is", "not set")}
|
||||
)
|
||||
|
||||
for asset in assets:
|
||||
asset = frappe.get_doc("Asset", asset.name)
|
||||
|
@ -4,11 +4,12 @@
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, getdate, today
|
||||
from frappe.utils import add_months, cint, flt, getdate, nowdate, today
|
||||
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_checks_for_pl_and_bs_accounts,
|
||||
)
|
||||
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
|
||||
|
||||
|
||||
def post_depreciation_entries(date=None, commit=True):
|
||||
@ -196,6 +197,11 @@ def scrap_asset(asset_name):
|
||||
_("Asset {0} cannot be scrapped, as it is already {1}").format(asset.name, asset.status)
|
||||
)
|
||||
|
||||
date = today()
|
||||
|
||||
depreciate_asset(asset, date)
|
||||
asset.reload()
|
||||
|
||||
depreciation_series = frappe.get_cached_value(
|
||||
"Company", asset.company, "series_for_depreciation_entry"
|
||||
)
|
||||
@ -203,7 +209,7 @@ def scrap_asset(asset_name):
|
||||
je = frappe.new_doc("Journal Entry")
|
||||
je.voucher_type = "Journal Entry"
|
||||
je.naming_series = depreciation_series
|
||||
je.posting_date = today()
|
||||
je.posting_date = date
|
||||
je.company = asset.company
|
||||
je.remark = "Scrap Entry for asset {0}".format(asset_name)
|
||||
|
||||
@ -214,7 +220,7 @@ def scrap_asset(asset_name):
|
||||
je.flags.ignore_permissions = True
|
||||
je.submit()
|
||||
|
||||
frappe.db.set_value("Asset", asset_name, "disposal_date", today())
|
||||
frappe.db.set_value("Asset", asset_name, "disposal_date", date)
|
||||
frappe.db.set_value("Asset", asset_name, "journal_entry_for_scrap", je.name)
|
||||
asset.set_status("Scrapped")
|
||||
|
||||
@ -225,6 +231,9 @@ def scrap_asset(asset_name):
|
||||
def restore_asset(asset_name):
|
||||
asset = frappe.get_doc("Asset", asset_name)
|
||||
|
||||
reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date)
|
||||
reset_depreciation_schedule(asset, asset.disposal_date)
|
||||
|
||||
je = asset.journal_entry_for_scrap
|
||||
|
||||
asset.db_set("disposal_date", None)
|
||||
@ -235,6 +244,91 @@ def restore_asset(asset_name):
|
||||
asset.set_status()
|
||||
|
||||
|
||||
def depreciate_asset(asset, date):
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
asset.prepare_depreciation_data(date_of_disposal=date)
|
||||
asset.save()
|
||||
|
||||
make_depreciation_entry(asset.name, date)
|
||||
|
||||
|
||||
def reset_depreciation_schedule(asset, date):
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
|
||||
# recreate original depreciation schedule of the asset
|
||||
asset.prepare_depreciation_data(date_of_return=date)
|
||||
|
||||
modify_depreciation_schedule_for_asset_repairs(asset)
|
||||
asset.save()
|
||||
|
||||
|
||||
def modify_depreciation_schedule_for_asset_repairs(asset):
|
||||
asset_repairs = frappe.get_all(
|
||||
"Asset Repair", filters={"asset": asset.name}, fields=["name", "increase_in_asset_life"]
|
||||
)
|
||||
|
||||
for repair in asset_repairs:
|
||||
if repair.increase_in_asset_life:
|
||||
asset_repair = frappe.get_doc("Asset Repair", repair.name)
|
||||
asset_repair.modify_depreciation_schedule()
|
||||
asset.prepare_depreciation_data()
|
||||
|
||||
|
||||
def reverse_depreciation_entry_made_after_disposal(asset, date):
|
||||
row = -1
|
||||
finance_book = asset.get("schedules")[0].get("finance_book")
|
||||
for schedule in asset.get("schedules"):
|
||||
if schedule.finance_book != finance_book:
|
||||
row = 0
|
||||
finance_book = schedule.finance_book
|
||||
else:
|
||||
row += 1
|
||||
|
||||
if schedule.schedule_date == date:
|
||||
if not disposal_was_made_on_original_schedule_date(
|
||||
asset, schedule, row, date
|
||||
) or disposal_happens_in_the_future(date):
|
||||
|
||||
reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
|
||||
reverse_journal_entry.posting_date = nowdate()
|
||||
frappe.flags.is_reverse_depr_entry = True
|
||||
reverse_journal_entry.submit()
|
||||
|
||||
frappe.flags.is_reverse_depr_entry = False
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
schedule.journal_entry = None
|
||||
depreciation_amount = get_depreciation_amount_in_je(reverse_journal_entry)
|
||||
asset.finance_books[0].value_after_depreciation += depreciation_amount
|
||||
asset.save()
|
||||
|
||||
|
||||
def get_depreciation_amount_in_je(journal_entry):
|
||||
if journal_entry.accounts[0].debit_in_account_currency:
|
||||
return journal_entry.accounts[0].debit_in_account_currency
|
||||
else:
|
||||
return journal_entry.accounts[0].credit_in_account_currency
|
||||
|
||||
|
||||
# if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone
|
||||
def disposal_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_disposal):
|
||||
for finance_book in asset.get("finance_books"):
|
||||
if schedule.finance_book == finance_book.finance_book:
|
||||
orginal_schedule_date = add_months(
|
||||
finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation)
|
||||
)
|
||||
|
||||
if orginal_schedule_date == posting_date_of_disposal:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def disposal_happens_in_the_future(posting_date_of_disposal):
|
||||
if posting_date_of_disposal > getdate():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_gl_entries_on_asset_regain(
|
||||
asset, selling_amount=0, finance_book=None, voucher_type=None, voucher_no=None
|
||||
):
|
||||
|
@ -4,10 +4,23 @@
|
||||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.utils import add_days, add_months, cstr, flt, get_last_day, getdate, nowdate
|
||||
from frappe.utils import (
|
||||
add_days,
|
||||
add_months,
|
||||
cstr,
|
||||
flt,
|
||||
get_first_day,
|
||||
get_last_day,
|
||||
getdate,
|
||||
nowdate,
|
||||
)
|
||||
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.assets.doctype.asset.asset import make_sales_invoice, split_asset
|
||||
from erpnext.assets.doctype.asset.asset import (
|
||||
make_sales_invoice,
|
||||
split_asset,
|
||||
update_maintenance_status,
|
||||
)
|
||||
from erpnext.assets.doctype.asset.depreciation import (
|
||||
post_depreciation_entries,
|
||||
restore_asset,
|
||||
@ -178,28 +191,48 @@ class TestAsset(AssetSetup):
|
||||
self.assertEqual(doc.items[0].is_fixed_asset, 1)
|
||||
|
||||
def test_scrap_asset(self):
|
||||
date = nowdate()
|
||||
purchase_date = add_months(get_first_day(date), -2)
|
||||
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
available_for_use_date="2020-01-01",
|
||||
purchase_date="2020-01-01",
|
||||
available_for_use_date=purchase_date,
|
||||
purchase_date=purchase_date,
|
||||
expected_value_after_useful_life=10000,
|
||||
total_number_of_depreciations=10,
|
||||
frequency_of_depreciation=1,
|
||||
submit=1,
|
||||
)
|
||||
|
||||
post_depreciation_entries(date=add_months("2020-01-01", 4))
|
||||
post_depreciation_entries(date=add_months(purchase_date, 2))
|
||||
asset.load_from_db()
|
||||
|
||||
accumulated_depr_amount = flt(
|
||||
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
|
||||
asset.precision("gross_purchase_amount"),
|
||||
)
|
||||
self.assertEquals(accumulated_depr_amount, 18000.0)
|
||||
|
||||
scrap_asset(asset.name)
|
||||
|
||||
asset.load_from_db()
|
||||
|
||||
accumulated_depr_amount = flt(
|
||||
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
|
||||
asset.precision("gross_purchase_amount"),
|
||||
)
|
||||
pro_rata_amount, _, _ = asset.get_pro_rata_amt(
|
||||
asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date
|
||||
)
|
||||
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
|
||||
self.assertEquals(accumulated_depr_amount, 18000.00 + pro_rata_amount)
|
||||
|
||||
self.assertEqual(asset.status, "Scrapped")
|
||||
self.assertTrue(asset.journal_entry_for_scrap)
|
||||
|
||||
expected_gle = (
|
||||
("_Test Accumulated Depreciations - _TC", 36000.0, 0.0),
|
||||
("_Test Accumulated Depreciations - _TC", 18000.0 + pro_rata_amount, 0.0),
|
||||
("_Test Fixed Asset - _TC", 0.0, 100000.0),
|
||||
("_Test Gain/Loss on Asset Disposal - _TC", 64000.0, 0.0),
|
||||
("_Test Gain/Loss on Asset Disposal - _TC", 82000.0 - pro_rata_amount, 0.0),
|
||||
)
|
||||
|
||||
gle = frappe.db.sql(
|
||||
@ -216,7 +249,64 @@ class TestAsset(AssetSetup):
|
||||
self.assertFalse(asset.journal_entry_for_scrap)
|
||||
self.assertEqual(asset.status, "Partially Depreciated")
|
||||
|
||||
accumulated_depr_amount = flt(
|
||||
asset.gross_purchase_amount - asset.finance_books[0].value_after_depreciation,
|
||||
asset.precision("gross_purchase_amount"),
|
||||
)
|
||||
this_month_depr_amount = 9000.0 if get_last_day(date) == date else 0
|
||||
|
||||
self.assertEquals(accumulated_depr_amount, 18000.0 + this_month_depr_amount)
|
||||
|
||||
def test_gle_made_by_asset_sale(self):
|
||||
date = nowdate()
|
||||
purchase_date = add_months(get_first_day(date), -2)
|
||||
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
available_for_use_date=purchase_date,
|
||||
purchase_date=purchase_date,
|
||||
expected_value_after_useful_life=10000,
|
||||
total_number_of_depreciations=10,
|
||||
frequency_of_depreciation=1,
|
||||
submit=1,
|
||||
)
|
||||
|
||||
post_depreciation_entries(date=add_months(purchase_date, 2))
|
||||
|
||||
si = make_sales_invoice(asset=asset.name, item_code="Macbook Pro", company="_Test Company")
|
||||
si.customer = "_Test Customer"
|
||||
si.due_date = nowdate()
|
||||
si.get("items")[0].rate = 25000
|
||||
si.insert()
|
||||
si.submit()
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
|
||||
|
||||
pro_rata_amount, _, _ = asset.get_pro_rata_amt(
|
||||
asset.finance_books[0], 9000, add_months(get_last_day(purchase_date), 1), date
|
||||
)
|
||||
pro_rata_amount = flt(pro_rata_amount, asset.precision("gross_purchase_amount"))
|
||||
|
||||
expected_gle = (
|
||||
("_Test Accumulated Depreciations - _TC", 18000.0 + pro_rata_amount, 0.0),
|
||||
("_Test Fixed Asset - _TC", 0.0, 100000.0),
|
||||
("_Test Gain/Loss on Asset Disposal - _TC", 57000.0 - pro_rata_amount, 0.0),
|
||||
("Debtors - _TC", 25000.0, 0.0),
|
||||
)
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select account, debit, credit from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no = %s
|
||||
order by account""",
|
||||
si.name,
|
||||
)
|
||||
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
si.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||
|
||||
def test_asset_with_maintenance_required_status_after_sale(self):
|
||||
asset = create_asset(
|
||||
calculate_depreciation=1,
|
||||
available_for_use_date="2020-06-06",
|
||||
@ -224,6 +314,7 @@ class TestAsset(AssetSetup):
|
||||
expected_value_after_useful_life=10000,
|
||||
total_number_of_depreciations=3,
|
||||
frequency_of_depreciation=10,
|
||||
maintenance_required=1,
|
||||
depreciation_start_date="2020-12-31",
|
||||
submit=1,
|
||||
)
|
||||
@ -239,24 +330,9 @@ class TestAsset(AssetSetup):
|
||||
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
|
||||
|
||||
expected_gle = (
|
||||
("_Test Accumulated Depreciations - _TC", 20490.2, 0.0),
|
||||
("_Test Fixed Asset - _TC", 0.0, 100000.0),
|
||||
("_Test Gain/Loss on Asset Disposal - _TC", 54509.8, 0.0),
|
||||
("Debtors - _TC", 25000.0, 0.0),
|
||||
)
|
||||
update_maintenance_status()
|
||||
|
||||
gle = frappe.db.sql(
|
||||
"""select account, debit, credit from `tabGL Entry`
|
||||
where voucher_type='Sales Invoice' and voucher_no = %s
|
||||
order by account""",
|
||||
si.name,
|
||||
)
|
||||
|
||||
self.assertSequenceEqual(gle, expected_gle)
|
||||
|
||||
si.cancel()
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold")
|
||||
|
||||
def test_asset_splitting(self):
|
||||
asset = create_asset(
|
||||
@ -1376,6 +1452,7 @@ def create_asset(**args):
|
||||
"number_of_depreciations_booked": args.number_of_depreciations_booked or 0,
|
||||
"gross_purchase_amount": args.gross_purchase_amount or 100000,
|
||||
"purchase_receipt_amount": args.purchase_receipt_amount or 100000,
|
||||
"maintenance_required": args.maintenance_required or 0,
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"available_for_use_date": args.available_for_use_date or "2020-06-06",
|
||||
"location": args.location or "Test Location",
|
||||
|
@ -12,8 +12,11 @@ from six import string_types
|
||||
|
||||
import erpnext
|
||||
from erpnext.assets.doctype.asset.depreciation import (
|
||||
depreciate_asset,
|
||||
get_gl_entries_on_asset_disposal,
|
||||
get_value_after_depreciation_on_disposal_date,
|
||||
reset_depreciation_schedule,
|
||||
reverse_depreciation_entry_made_after_disposal,
|
||||
)
|
||||
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
|
||||
from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import (
|
||||
@ -424,7 +427,7 @@ class AssetCapitalization(StockController):
|
||||
asset = self.get_asset(item)
|
||||
|
||||
if asset.calculate_depreciation:
|
||||
self.depreciate_asset(asset)
|
||||
depreciate_asset(asset, self.posting_date)
|
||||
asset.reload()
|
||||
|
||||
fixed_asset_gl_entries = get_gl_entries_on_asset_disposal(
|
||||
@ -520,8 +523,8 @@ class AssetCapitalization(StockController):
|
||||
self.set_consumed_asset_status(asset)
|
||||
|
||||
if asset.calculate_depreciation:
|
||||
self.reverse_depreciation_entry_made_after_disposal(asset)
|
||||
self.reset_depreciation_schedule(asset)
|
||||
reverse_depreciation_entry_made_after_disposal(asset, self.posting_date)
|
||||
reset_depreciation_schedule(asset, self.posting_date)
|
||||
|
||||
def get_asset(self, item):
|
||||
asset = frappe.get_doc("Asset", item.asset)
|
||||
|
@ -20,7 +20,6 @@
|
||||
"maintain_same_rate",
|
||||
"allow_multiple_items",
|
||||
"bill_for_rejected_quantity_in_purchase_invoice",
|
||||
"enable_discount_accounting",
|
||||
"subcontract",
|
||||
"backflush_raw_materials_of_subcontract_based_on",
|
||||
"column_break_11",
|
||||
@ -134,13 +133,6 @@
|
||||
{
|
||||
"fieldname": "column_break_12",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If enabled, additional ledger entries will be made for discounts in a separate Discount Account",
|
||||
"fieldname": "enable_discount_accounting",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enable Discount Accounting for Buying"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
@ -148,7 +140,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2022-09-01 18:01:34.994657",
|
||||
"modified": "2022-09-27 10:50:27.050252",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Buying Settings",
|
||||
|
@ -5,15 +5,10 @@
|
||||
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
class BuyingSettings(Document):
|
||||
def on_update(self):
|
||||
self.toggle_discount_accounting_fields()
|
||||
|
||||
def validate(self):
|
||||
for key in ["supplier_group", "supp_master_name", "maintain_same_rate", "buying_price_list"]:
|
||||
frappe.db.set_default(key, self.get(key, ""))
|
||||
@ -26,60 +21,3 @@ class BuyingSettings(Document):
|
||||
self.get("supp_master_name") == "Naming Series",
|
||||
hide_name_field=False,
|
||||
)
|
||||
|
||||
def toggle_discount_accounting_fields(self):
|
||||
enable_discount_accounting = cint(self.enable_discount_accounting)
|
||||
|
||||
make_property_setter(
|
||||
"Purchase Invoice Item",
|
||||
"discount_account",
|
||||
"hidden",
|
||||
not (enable_discount_accounting),
|
||||
"Check",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
if enable_discount_accounting:
|
||||
make_property_setter(
|
||||
"Purchase Invoice Item",
|
||||
"discount_account",
|
||||
"mandatory_depends_on",
|
||||
"eval: doc.discount_amount",
|
||||
"Code",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
else:
|
||||
make_property_setter(
|
||||
"Purchase Invoice Item",
|
||||
"discount_account",
|
||||
"mandatory_depends_on",
|
||||
"",
|
||||
"Code",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
|
||||
make_property_setter(
|
||||
"Purchase Invoice",
|
||||
"additional_discount_account",
|
||||
"hidden",
|
||||
not (enable_discount_accounting),
|
||||
"Check",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
if enable_discount_accounting:
|
||||
make_property_setter(
|
||||
"Purchase Invoice",
|
||||
"additional_discount_account",
|
||||
"mandatory_depends_on",
|
||||
"eval: doc.discount_amount",
|
||||
"Code",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
else:
|
||||
make_property_setter(
|
||||
"Purchase Invoice",
|
||||
"additional_discount_account",
|
||||
"mandatory_depends_on",
|
||||
"",
|
||||
"Code",
|
||||
validate_fields_for_doctype=False,
|
||||
)
|
||||
|
@ -33,6 +33,7 @@ frappe.ui.form.on("Purchase Order", {
|
||||
frm.set_query("fg_item", "items", function() {
|
||||
return {
|
||||
filters: {
|
||||
'is_stock_item': 1,
|
||||
'is_sub_contracted_item': 1,
|
||||
'default_bom': ['!=', '']
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ from erpnext.accounts.party import (
|
||||
validate_party_frozen_disabled,
|
||||
)
|
||||
from erpnext.accounts.utils import get_account_currency, get_fiscal_years, validate_fiscal_year
|
||||
from erpnext.assets.doctype.asset.depreciation import make_depreciation_entry
|
||||
from erpnext.buying.utils import update_last_purchase_rate
|
||||
from erpnext.controllers.print_settings import (
|
||||
set_print_templates_for_item_table,
|
||||
@ -1891,88 +1890,6 @@ class AccountsController(TransactionBase):
|
||||
_("Select finance book for the item {0} at row {1}").format(item.item_code, item.idx)
|
||||
)
|
||||
|
||||
def depreciate_asset(self, asset):
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
asset.prepare_depreciation_data(date_of_disposal=self.posting_date)
|
||||
asset.save()
|
||||
|
||||
make_depreciation_entry(asset.name, self.posting_date)
|
||||
|
||||
def reset_depreciation_schedule(self, asset):
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
|
||||
# recreate original depreciation schedule of the asset
|
||||
asset.prepare_depreciation_data(date_of_return=self.posting_date)
|
||||
|
||||
self.modify_depreciation_schedule_for_asset_repairs(asset)
|
||||
asset.save()
|
||||
|
||||
def modify_depreciation_schedule_for_asset_repairs(self, asset):
|
||||
asset_repairs = frappe.get_all(
|
||||
"Asset Repair", filters={"asset": asset.name}, fields=["name", "increase_in_asset_life"]
|
||||
)
|
||||
|
||||
for repair in asset_repairs:
|
||||
if repair.increase_in_asset_life:
|
||||
asset_repair = frappe.get_doc("Asset Repair", repair.name)
|
||||
asset_repair.modify_depreciation_schedule()
|
||||
asset.prepare_depreciation_data()
|
||||
|
||||
def reverse_depreciation_entry_made_after_disposal(self, asset):
|
||||
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
|
||||
|
||||
posting_date_of_original_disposal = self.get_posting_date_of_disposal_entry()
|
||||
|
||||
row = -1
|
||||
finance_book = asset.get("schedules")[0].get("finance_book")
|
||||
for schedule in asset.get("schedules"):
|
||||
if schedule.finance_book != finance_book:
|
||||
row = 0
|
||||
finance_book = schedule.finance_book
|
||||
else:
|
||||
row += 1
|
||||
|
||||
if schedule.schedule_date == posting_date_of_original_disposal:
|
||||
if not self.disposal_was_made_on_original_schedule_date(
|
||||
asset, schedule, row, posting_date_of_original_disposal
|
||||
) or self.disposal_happens_in_the_future(posting_date_of_original_disposal):
|
||||
|
||||
reverse_journal_entry = make_reverse_journal_entry(schedule.journal_entry)
|
||||
reverse_journal_entry.posting_date = nowdate()
|
||||
frappe.flags.is_reverse_depr_entry = True
|
||||
reverse_journal_entry.submit()
|
||||
|
||||
frappe.flags.is_reverse_depr_entry = False
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
schedule.journal_entry = None
|
||||
asset.save()
|
||||
|
||||
def get_posting_date_of_disposal_entry(self):
|
||||
if self.doctype == "Sales Invoice" and self.return_against:
|
||||
return frappe.db.get_value("Sales Invoice", self.return_against, "posting_date")
|
||||
else:
|
||||
return self.posting_date
|
||||
|
||||
# if the invoice had been posted on the date the depreciation was initially supposed to happen, the depreciation shouldn't be undone
|
||||
def disposal_was_made_on_original_schedule_date(
|
||||
self, asset, schedule, row, posting_date_of_disposal
|
||||
):
|
||||
for finance_book in asset.get("finance_books"):
|
||||
if schedule.finance_book == finance_book.finance_book:
|
||||
orginal_schedule_date = add_months(
|
||||
finance_book.depreciation_start_date, row * cint(finance_book.frequency_of_depreciation)
|
||||
)
|
||||
|
||||
if orginal_schedule_date == posting_date_of_disposal:
|
||||
return True
|
||||
return False
|
||||
|
||||
def disposal_happens_in_the_future(self, posting_date_of_disposal):
|
||||
if posting_date_of_disposal > getdate():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_tax_rate(account_head):
|
||||
|
@ -212,21 +212,15 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
meta = frappe.get_meta(doctype, cached=True)
|
||||
searchfields = meta.get_search_fields()
|
||||
|
||||
# these are handled separately
|
||||
ignored_search_fields = ("item_name", "description")
|
||||
for ignored_field in ignored_search_fields:
|
||||
if ignored_field in searchfields:
|
||||
searchfields.remove(ignored_field)
|
||||
|
||||
columns = ""
|
||||
extra_searchfields = [
|
||||
field
|
||||
for field in searchfields
|
||||
if not field in ["name", "item_group", "description", "item_name"]
|
||||
]
|
||||
extra_searchfields = [field for field in searchfields if not field in ["name", "description"]]
|
||||
|
||||
if extra_searchfields:
|
||||
columns = ", " + ", ".join(extra_searchfields)
|
||||
columns += ", " + ", ".join(extra_searchfields)
|
||||
|
||||
if "description" in searchfields:
|
||||
columns += """, if(length(tabItem.description) > 40, \
|
||||
concat(substr(tabItem.description, 1, 40), "..."), description) as description"""
|
||||
|
||||
searchfields = searchfields + [
|
||||
field
|
||||
@ -266,12 +260,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
|
||||
if frappe.db.count(doctype, cache=True) < 50000:
|
||||
# scan description only if items are less than 50000
|
||||
description_cond = "or tabItem.description LIKE %(txt)s"
|
||||
|
||||
return frappe.db.sql(
|
||||
"""select
|
||||
tabItem.name, tabItem.item_name, tabItem.item_group,
|
||||
if(length(tabItem.description) > 40, \
|
||||
concat(substr(tabItem.description, 1, 40), "..."), description) as description
|
||||
{columns}
|
||||
tabItem.name {columns}
|
||||
from tabItem
|
||||
where tabItem.docstatus < 2
|
||||
and tabItem.disabled=0
|
||||
|
@ -69,9 +69,18 @@ class SubcontractingController(StockController):
|
||||
|
||||
def validate_items(self):
|
||||
for item in self.items:
|
||||
if not frappe.get_value("Item", item.item_code, "is_sub_contracted_item"):
|
||||
is_stock_item, is_sub_contracted_item = frappe.get_value(
|
||||
"Item", item.item_code, ["is_stock_item", "is_sub_contracted_item"]
|
||||
)
|
||||
|
||||
if not is_stock_item:
|
||||
msg = f"Item {item.item_name} must be a stock item."
|
||||
frappe.throw(_(msg))
|
||||
|
||||
if not is_sub_contracted_item:
|
||||
msg = f"Item {item.item_name} must be a subcontracted item."
|
||||
frappe.throw(_(msg))
|
||||
|
||||
if item.bom:
|
||||
bom = frappe.get_doc("BOM", item.bom)
|
||||
if not bom.is_active:
|
||||
@ -841,7 +850,7 @@ def make_rm_stock_entry(
|
||||
for fg_item_code in fg_item_code_list:
|
||||
for rm_item in rm_items:
|
||||
|
||||
if rm_item.get("main_item_code") or rm_item.get("item_code") == fg_item_code:
|
||||
if rm_item.get("main_item_code") == fg_item_code or rm_item.get("item_code") == fg_item_code:
|
||||
rm_item_code = rm_item.get("rm_item_code")
|
||||
|
||||
items_dict = {
|
||||
|
@ -188,7 +188,8 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Item Group",
|
||||
"options": "Item Group",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
@ -234,7 +235,8 @@
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Link",
|
||||
"label": "Brand",
|
||||
"options": "Brand"
|
||||
"options": "Brand",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
@ -346,7 +348,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"make_attachments_public": 1,
|
||||
"modified": "2022-09-13 04:05:11.614087",
|
||||
"modified": "2022-09-30 04:01:52.090732",
|
||||
"modified_by": "Administrator",
|
||||
"module": "E-commerce",
|
||||
"name": "Website Item",
|
||||
|
@ -403,9 +403,6 @@ def on_doctype_update():
|
||||
# since route is a Text column, it needs a length for indexing
|
||||
frappe.db.add_index("Website Item", ["route(500)"])
|
||||
|
||||
frappe.db.add_index("Website Item", ["item_group"])
|
||||
frappe.db.add_index("Website Item", ["brand"])
|
||||
|
||||
|
||||
def check_if_user_is_customer(user=None):
|
||||
from frappe.contacts.doctype.contact.contact import get_contact_name
|
||||
|
@ -391,12 +391,12 @@ scheduler_events = {
|
||||
"erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts",
|
||||
],
|
||||
"hourly": [
|
||||
"erpnext.accounts.doctype.subscription.subscription.process_all",
|
||||
"erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization",
|
||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||
],
|
||||
"hourly_long": [
|
||||
"erpnext.accounts.doctype.subscription.subscription.process_all",
|
||||
"erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries",
|
||||
"erpnext.bulk_transaction.doctype.bulk_transaction_log.bulk_transaction_log.retry_failing_transaction",
|
||||
],
|
||||
@ -508,6 +508,7 @@ accounting_dimension_doctypes = [
|
||||
"Landed Cost Item",
|
||||
"Asset Value Adjustment",
|
||||
"Asset Repair",
|
||||
"Asset Capitalization",
|
||||
"Loyalty Program",
|
||||
"Stock Reconciliation",
|
||||
"POS Profile",
|
||||
|
@ -315,3 +315,4 @@ erpnext.patches.v14_0.fix_crm_no_of_employees
|
||||
erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
|
||||
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
|
||||
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
|
||||
erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
|
||||
|
@ -100,6 +100,7 @@ def execute():
|
||||
"mode_of_payment": loan.mode_of_payment,
|
||||
"loan_account": loan.loan_account,
|
||||
"payment_account": loan.payment_account,
|
||||
"disbursement_account": loan.payment_account,
|
||||
"interest_income_account": loan.interest_income_account,
|
||||
"penalty_income_account": loan.penalty_income_account,
|
||||
},
|
||||
@ -190,6 +191,7 @@ def create_loan_type(loan, loan_type_name, penalty_account):
|
||||
loan_type_doc.company = loan.company
|
||||
loan_type_doc.mode_of_payment = loan.mode_of_payment
|
||||
loan_type_doc.payment_account = loan.payment_account
|
||||
loan_type_doc.disbursement_account = loan.payment_account
|
||||
loan_type_doc.loan_account = loan.loan_account
|
||||
loan_type_doc.interest_income_account = loan.interest_income_account
|
||||
loan_type_doc.penalty_income_account = penalty_account
|
||||
|
@ -0,0 +1,31 @@
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
|
||||
|
||||
def execute():
|
||||
accounting_dimensions = frappe.db.get_all(
|
||||
"Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"]
|
||||
)
|
||||
|
||||
if not accounting_dimensions:
|
||||
return
|
||||
|
||||
doctype = "Asset Capitalization"
|
||||
|
||||
for d in accounting_dimensions:
|
||||
field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
|
||||
|
||||
if field:
|
||||
continue
|
||||
|
||||
df = {
|
||||
"fieldname": d.fieldname,
|
||||
"label": d.label,
|
||||
"fieldtype": "Link",
|
||||
"options": d.document_type,
|
||||
"insert_after": "accounting_dimensions_section",
|
||||
}
|
||||
|
||||
create_custom_field(doctype, df, ignore_validate=True)
|
||||
|
||||
frappe.clear_cache(doctype=doctype)
|
@ -3,6 +3,29 @@ from frappe import qb
|
||||
from frappe.utils import create_batch
|
||||
|
||||
|
||||
def remove_duplicate_entries(pl_entries):
|
||||
unique_vouchers = set()
|
||||
for x in pl_entries:
|
||||
unique_vouchers.add(
|
||||
(x.company, x.account, x.party_type, x.party, x.voucher_type, x.voucher_no, x.gle_remarks)
|
||||
)
|
||||
|
||||
entries = []
|
||||
for x in unique_vouchers:
|
||||
entries.append(
|
||||
frappe._dict(
|
||||
company=x[0],
|
||||
account=x[1],
|
||||
party_type=x[2],
|
||||
party=x[3],
|
||||
voucher_type=x[4],
|
||||
voucher_no=x[5],
|
||||
gle_remarks=x[6],
|
||||
)
|
||||
)
|
||||
return entries
|
||||
|
||||
|
||||
def execute():
|
||||
if frappe.reload_doc("accounts", "doctype", "payment_ledger_entry"):
|
||||
|
||||
@ -34,6 +57,8 @@ def execute():
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
pl_entries = remove_duplicate_entries(pl_entries)
|
||||
|
||||
if pl_entries:
|
||||
# split into multiple batches, update and commit for each batch
|
||||
batch_size = 1000
|
||||
|
115
erpnext/public/scss/order-page.scss
Normal file
115
erpnext/public/scss/order-page.scss
Normal file
@ -0,0 +1,115 @@
|
||||
#page-order {
|
||||
.main-column {
|
||||
.page-content-wrapper {
|
||||
|
||||
.breadcrumb-container {
|
||||
@media screen and (min-width: 567px) {
|
||||
padding-left: var(--padding-sm);
|
||||
}
|
||||
}
|
||||
|
||||
.container.my-4 {
|
||||
background-color: var(--fg-color);
|
||||
|
||||
@media screen and (min-width: 567px) {
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-radius: var(--border-radius-md);
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.indicator-container {
|
||||
@media screen and (max-width: 567px) {
|
||||
padding-bottom: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.order-items {
|
||||
padding: 1.5rem 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
color: var(--gray-700);
|
||||
|
||||
@media screen and (max-width: 567px) {
|
||||
align-items: flex-start !important;
|
||||
}
|
||||
.col-2 {
|
||||
@media screen and (max-width: 567px) {
|
||||
flex: auto;
|
||||
max-width: 28%;
|
||||
}
|
||||
}
|
||||
|
||||
.order-item-name {
|
||||
font-size: var(--text-base);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.btn:focus,
|
||||
.btn:hover {
|
||||
background-color: var(--control-bg);
|
||||
}
|
||||
|
||||
|
||||
.col-6 {
|
||||
@media screen and (max-width: 567px) {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&.order-item-name {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-grand-total {
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.list-item-name,
|
||||
.item-total,
|
||||
.order-container,
|
||||
.order-qty {
|
||||
font-size: var(--text-md);
|
||||
}
|
||||
|
||||
.d-s-n {
|
||||
@media screen and (max-width: 567px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.d-l-n {
|
||||
@media screen and (min-width: 567px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.border-btm {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.order-taxes {
|
||||
display: flex;
|
||||
|
||||
@media screen and (min-width: 567px) {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.col-4 {
|
||||
padding-right: 0;
|
||||
|
||||
.col-8 {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 567px) {
|
||||
padding-left: 0;
|
||||
flex: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
@import './order-page';
|
||||
|
||||
.filter-options {
|
||||
max-height: 300px;
|
||||
@ -32,19 +33,29 @@
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.website-list .result {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.website-list {
|
||||
background-color: var(--fg-color);
|
||||
padding: 0 var(--padding-lg);
|
||||
border-radius: var(--border-radius-md);
|
||||
|
||||
.result {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
@media screen and (max-width: 567px) {
|
||||
margin-left: -2rem;
|
||||
}
|
||||
|
||||
&.result {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
}
|
||||
|
||||
.transaction-list-item {
|
||||
padding: 1rem 0;
|
||||
border-top: 1px solid var(--border-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
position: relative;
|
||||
|
||||
&:only-child, &:last-child {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
a.transaction-item-link {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -68,3 +79,13 @@
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item-name, .item-total {
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.items-preview {
|
||||
@media screen and (max-width: 567px) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
@ -660,7 +660,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (available_qty < qty_needed) {
|
||||
} else if (is_stock_item && available_qty < qty_needed) {
|
||||
frappe.throw({
|
||||
message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.', [bold_item_code, bold_warehouse, bold_available_qty]),
|
||||
indicator: 'orange'
|
||||
@ -694,7 +694,7 @@ erpnext.PointOfSale.Controller = class {
|
||||
callback(res) {
|
||||
if (!me.item_stock_map[item_code])
|
||||
me.item_stock_map[item_code] = {};
|
||||
me.item_stock_map[item_code][warehouse] = res.message[0];
|
||||
me.item_stock_map[item_code][warehouse] = res.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -242,13 +242,14 @@ erpnext.PointOfSale.ItemDetails = class {
|
||||
if (this.value) {
|
||||
me.events.form_updated(me.current_item, 'warehouse', this.value).then(() => {
|
||||
me.item_stock_map = me.events.get_item_stock_map();
|
||||
const available_qty = me.item_stock_map[me.item_row.item_code] && me.item_stock_map[me.item_row.item_code][this.value];
|
||||
const available_qty = me.item_stock_map[me.item_row.item_code][this.value][0];
|
||||
const is_stock_item = Boolean(me.item_stock_map[me.item_row.item_code][this.value][1]);
|
||||
if (available_qty === undefined) {
|
||||
me.events.get_available_stock(me.item_row.item_code, this.value).then(() => {
|
||||
// item stock map is updated now reset warehouse
|
||||
me.warehouse_control.set_value(this.value);
|
||||
})
|
||||
} else if (available_qty === 0) {
|
||||
} else if (available_qty === 0 && is_stock_item) {
|
||||
me.warehouse_control.set_value('');
|
||||
const bold_item_code = me.item_row.item_code.bold();
|
||||
const bold_warehouse = this.value.bold();
|
||||
|
@ -37,8 +37,10 @@ class Bin(Document):
|
||||
|
||||
self.set_projected_qty()
|
||||
|
||||
self.db_set("reserved_qty_for_production", flt(self.reserved_qty_for_production))
|
||||
self.db_set("projected_qty", self.projected_qty)
|
||||
self.db_set(
|
||||
"reserved_qty_for_production", flt(self.reserved_qty_for_production), update_modified=True
|
||||
)
|
||||
self.db_set("projected_qty", self.projected_qty, update_modified=True)
|
||||
|
||||
def update_reserved_qty_for_sub_contracting(self, subcontract_doctype="Subcontracting Order"):
|
||||
# reserved qty
|
||||
@ -118,9 +120,9 @@ class Bin(Document):
|
||||
else:
|
||||
reserved_qty_for_sub_contract = 0
|
||||
|
||||
self.db_set("reserved_qty_for_sub_contract", reserved_qty_for_sub_contract)
|
||||
self.db_set("reserved_qty_for_sub_contract", reserved_qty_for_sub_contract, update_modified=True)
|
||||
self.set_projected_qty()
|
||||
self.db_set("projected_qty", self.projected_qty)
|
||||
self.db_set("projected_qty", self.projected_qty, update_modified=True)
|
||||
|
||||
|
||||
def on_doctype_update():
|
||||
@ -193,4 +195,5 @@ def update_qty(bin_name, args):
|
||||
"planned_qty": planned_qty,
|
||||
"projected_qty": projected_qty,
|
||||
},
|
||||
update_modified=True,
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ import json
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
from frappe.utils import cstr, flt, nowdate, nowtime
|
||||
from frappe.utils import add_days, cstr, flt, nowdate, nowtime, today
|
||||
|
||||
from erpnext.accounts.doctype.account.test_account import get_inventory_account
|
||||
from erpnext.accounts.utils import get_balance_on
|
||||
@ -1091,6 +1091,36 @@ class TestDeliveryNote(FrappeTestCase):
|
||||
frappe.db.exists("GL Entry", {"voucher_no": dn.name, "voucher_type": dn.doctype})
|
||||
)
|
||||
|
||||
def test_batch_expiry_for_delivery_note(self):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
|
||||
item = make_item(
|
||||
"_Test Batch Item For Return Check",
|
||||
{
|
||||
"is_purchase_item": 1,
|
||||
"is_stock_item": 1,
|
||||
"has_batch_no": 1,
|
||||
"create_new_batch": 1,
|
||||
"batch_number_series": "TBIRC.#####",
|
||||
},
|
||||
)
|
||||
|
||||
pi = make_purchase_receipt(qty=1, item_code=item.name)
|
||||
|
||||
dn = create_delivery_note(qty=1, item_code=item.name, batch_no=pi.items[0].batch_no)
|
||||
|
||||
dn.load_from_db()
|
||||
batch_no = dn.items[0].batch_no
|
||||
self.assertTrue(batch_no)
|
||||
|
||||
frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1))
|
||||
|
||||
return_dn = make_return_doc(dn.doctype, dn.name)
|
||||
return_dn.save().submit()
|
||||
|
||||
self.assertTrue(return_dn.docstatus == 1)
|
||||
|
||||
|
||||
def create_delivery_note(**args):
|
||||
dn = frappe.new_doc("Delivery Note")
|
||||
@ -1117,6 +1147,7 @@ def create_delivery_note(**args):
|
||||
"expense_account": args.expense_account or "Cost of Goods Sold - _TC",
|
||||
"cost_center": args.cost_center or "_Test Cost Center - _TC",
|
||||
"serial_no": args.serial_no,
|
||||
"batch_no": args.batch_no or None,
|
||||
"target_warehouse": args.target_warehouse,
|
||||
},
|
||||
)
|
||||
|
@ -10,6 +10,31 @@ frappe.ui.form.on("Item", {
|
||||
frm.add_fetch('attribute', 'to_range', 'to_range');
|
||||
frm.add_fetch('attribute', 'increment', 'increment');
|
||||
frm.add_fetch('tax_type', 'tax_rate', 'tax_rate');
|
||||
|
||||
frm.make_methods = {
|
||||
'Sales Order': () => {
|
||||
open_form(frm, "Sales Order", "Sales Order Item", "items");
|
||||
},
|
||||
'Delivery Note': () => {
|
||||
open_form(frm, "Delivery Note", "Delivery Note Item", "items");
|
||||
},
|
||||
'Sales Invoice': () => {
|
||||
open_form(frm, "Sales Invoice", "Sales Invoice Item", "items");
|
||||
},
|
||||
'Purchase Order': () => {
|
||||
open_form(frm, "Purchase Order", "Purchase Order Item", "items");
|
||||
},
|
||||
'Purchase Receipt': () => {
|
||||
open_form(frm, "Purchase Receipt", "Purchase Receipt Item", "items");
|
||||
},
|
||||
'Purchase Invoice': () => {
|
||||
open_form(frm, "Purchase Invoice", "Purchase Invoice Item", "items");
|
||||
},
|
||||
'Material Request': () => {
|
||||
open_form(frm, "Material Request", "Material Request Item", "items");
|
||||
},
|
||||
};
|
||||
|
||||
},
|
||||
onload: function(frm) {
|
||||
erpnext.item.setup_queries(frm);
|
||||
@ -858,3 +883,17 @@ frappe.tour['Item'] = [
|
||||
|
||||
|
||||
];
|
||||
|
||||
function open_form(frm, doctype, child_doctype, parentfield) {
|
||||
frappe.model.with_doctype(doctype, () => {
|
||||
let new_doc = frappe.model.get_new_doc(doctype);
|
||||
|
||||
let new_child_doc = frappe.model.add_child(new_doc, child_doctype, parentfield);
|
||||
new_child_doc.item_code = frm.doc.name;
|
||||
new_child_doc.item_name = frm.doc.item_name;
|
||||
new_child_doc.uom = frm.doc.stock_uom;
|
||||
new_child_doc.description = frm.doc.description;
|
||||
|
||||
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
|
||||
});
|
||||
}
|
||||
|
@ -937,17 +937,21 @@ class Item(Document):
|
||||
"Purchase Order Item",
|
||||
"Material Request Item",
|
||||
"Product Bundle",
|
||||
"BOM",
|
||||
]
|
||||
|
||||
for doctype in linked_doctypes:
|
||||
filters = {"item_code": self.name, "docstatus": 1}
|
||||
|
||||
if doctype == "Product Bundle":
|
||||
filters = {"new_item_code": self.name}
|
||||
if doctype in ("Product Bundle", "BOM"):
|
||||
if doctype == "Product Bundle":
|
||||
filters = {"new_item_code": self.name}
|
||||
fieldname = "new_item_code as docname"
|
||||
else:
|
||||
filters = {"item": self.name, "docstatus": 1}
|
||||
fieldname = "name as docname"
|
||||
|
||||
if linked_doc := frappe.db.get_value(
|
||||
doctype, filters, ["new_item_code as docname"], as_dict=True
|
||||
):
|
||||
if linked_doc := frappe.db.get_value(doctype, filters, fieldname, as_dict=True):
|
||||
return linked_doc.update({"doctype": doctype})
|
||||
|
||||
elif doctype in (
|
||||
|
@ -5,6 +5,7 @@
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
from frappe.test_runner import make_test_objects
|
||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||
from frappe.utils import add_days, today
|
||||
@ -816,6 +817,30 @@ class TestItem(FrappeTestCase):
|
||||
item.reload()
|
||||
self.assertEqual(item.is_stock_item, 1)
|
||||
|
||||
def test_serach_fields_for_item(self):
|
||||
from erpnext.controllers.queries import item_query
|
||||
|
||||
make_property_setter("Item", None, "search_fields", "item_name", "Data", for_doctype="Doctype")
|
||||
|
||||
item = make_item(properties={"item_name": "Test Item", "description": "Test Description"})
|
||||
data = item_query(
|
||||
"Item", "Test Item", "", 0, 20, filters={"item_name": "Test Item"}, as_dict=True
|
||||
)
|
||||
self.assertEqual(data[0].name, item.name)
|
||||
self.assertEqual(data[0].item_name, item.item_name)
|
||||
self.assertTrue("description" not in data[0])
|
||||
|
||||
make_property_setter(
|
||||
"Item", None, "search_fields", "item_name, description", "Data", for_doctype="Doctype"
|
||||
)
|
||||
data = item_query(
|
||||
"Item", "Test Item", "", 0, 20, filters={"item_name": "Test Item"}, as_dict=True
|
||||
)
|
||||
self.assertEqual(data[0].name, item.name)
|
||||
self.assertEqual(data[0].item_name, item.item_name)
|
||||
self.assertEqual(data[0].description, item.description)
|
||||
self.assertTrue("description" in data[0])
|
||||
|
||||
|
||||
def set_item_variant_settings(fields):
|
||||
doc = frappe.get_doc("Item Variant Settings")
|
||||
|
@ -183,7 +183,7 @@ class PickList(Document):
|
||||
frappe.throw("Row #{0}: Item Code is Mandatory".format(item.idx))
|
||||
item_code = item.item_code
|
||||
reference = item.sales_order_item or item.material_request_item
|
||||
key = (item_code, item.uom, item.warehouse, reference)
|
||||
key = (item_code, item.uom, item.warehouse, item.batch_no, reference)
|
||||
|
||||
item.idx = None
|
||||
item.name = None
|
||||
|
@ -128,6 +128,9 @@ def repost(doc):
|
||||
if not frappe.db.exists("Repost Item Valuation", doc.name):
|
||||
return
|
||||
|
||||
# This is to avoid TooManyWritesError in case of large reposts
|
||||
frappe.db.MAX_WRITES_PER_TRANSACTION *= 4
|
||||
|
||||
doc.set_status("In Progress")
|
||||
if not frappe.flags.in_test:
|
||||
frappe.db.commit()
|
||||
|
@ -153,7 +153,9 @@ class StockLedgerEntry(Document):
|
||||
|
||||
def validate_batch(self):
|
||||
if self.batch_no and self.voucher_type != "Stock Entry":
|
||||
if self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0:
|
||||
if (self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0) or (
|
||||
self.voucher_type in ["Delivery Note", "Sales Invoice"] and self.actual_qty > 0
|
||||
):
|
||||
return
|
||||
|
||||
expiry_date = frappe.db.get_value("Batch", self.batch_no, "expiry_date")
|
||||
|
@ -1053,7 +1053,7 @@ class update_entries_after(object):
|
||||
updated_values = {"actual_qty": data.qty_after_transaction, "stock_value": data.stock_value}
|
||||
if data.valuation_rate is not None:
|
||||
updated_values["valuation_rate"] = data.valuation_rate
|
||||
frappe.db.set_value("Bin", bin_name, updated_values)
|
||||
frappe.db.set_value("Bin", bin_name, updated_values, update_modified=True)
|
||||
|
||||
|
||||
def get_previous_sle_of_current_voucher(args, exclude_current_voucher=False):
|
||||
|
@ -6,7 +6,7 @@
|
||||
aria-label="{{ _('Your email address...') }}"
|
||||
aria-describedby="footer-subscribe-button">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-sm btn-default"
|
||||
<button class="btn btn-sm btn-secondary pl-3 pr-3 ml-2"
|
||||
type="button" id="footer-subscribe-button">{{ _("Get Updates") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% macro product_image_square(website_image, css_class="") %}
|
||||
<div class="product-image product-image-square
|
||||
<div class="product-image product-image-square h-100 rounded
|
||||
{% if not website_image -%} missing-image {%- endif %} {{ css_class }}"
|
||||
{% if website_image -%}
|
||||
style="background-image: url('{{ frappe.utils.quoted(website_image) | abs_url }}');"
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% macro item_name_and_description(d) %}
|
||||
<div class="row item_name_and_description">
|
||||
<div class="col-xs-4 col-sm-2 order-image-col">
|
||||
<div class="order-image">
|
||||
<div class="order-image h-100">
|
||||
{% if d.thumbnail or d.image %}
|
||||
{{ product_image(d.thumbnail or d.image, no_border=True) }}
|
||||
{% else %}
|
||||
@ -18,6 +18,9 @@
|
||||
<div class="text-muted small item-description">
|
||||
{{ html2text(d.description) | truncate(140) }}
|
||||
</div>
|
||||
<span class="text-muted mt-2 d-l-n order-qty">
|
||||
{{ _("Qty ") }}({{ d.get_formatted("qty") }})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
@ -1,84 +1,111 @@
|
||||
{% if doc.taxes %}
|
||||
<tr>
|
||||
<td class="text-left" colspan="1">
|
||||
{{ _("Net Total") }}
|
||||
</td>
|
||||
<td class="text-right totals" colspan="3">
|
||||
{{ doc.get_formatted("net_total") }}
|
||||
</td>
|
||||
</tr>
|
||||
<div class="w-100 order-taxes mt-5">
|
||||
<div class="col-4 d-flex border-btm pb-5">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Net Total") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
{{ doc.get_formatted("net_total") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for d in doc.taxes %}
|
||||
{% if d.base_tax_amount %}
|
||||
<tr>
|
||||
<td class="text-left" colspan="1">
|
||||
{{ d.description }}
|
||||
</td>
|
||||
<td class="text-right totals" colspan="3">
|
||||
{{ d.get_formatted("base_tax_amount") }}
|
||||
</td>
|
||||
</tr>
|
||||
<div class="order-taxes w-100 mt-5">
|
||||
<div class="col-4 d-flex border-btm pb-5">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ d.description }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
{{ doc.get_formatted("net_total") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if doc.doctype == 'Quotation' %}
|
||||
{% if doc.coupon_code %}
|
||||
<tr>
|
||||
<td class="text-left total-discount" colspan="1">
|
||||
{{ _("Savings") }}
|
||||
</td>
|
||||
<td class="text-right tot_quotation_discount total-discount totals" colspan="3">
|
||||
{% set tot_quotation_discount = [] %}
|
||||
{%- for item in doc.items -%}
|
||||
{% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
|
||||
* item.discount_percentage) / 100)) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }}
|
||||
</td>
|
||||
</tr>
|
||||
<div class="w-100 mt-5 order-taxes font-weight-bold">
|
||||
<div class="col-4 d-flex border-btm pb-5">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Savings") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
{% set tot_quotation_discount = [] %}
|
||||
{%- for item in doc.items -%}
|
||||
{% if tot_quotation_discount.append((((item.price_list_rate * item.qty)
|
||||
* item.discount_percentage) / 100)) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ frappe.utils.fmt_money((tot_quotation_discount | sum),currency=doc.currency) }} </div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if doc.doctype == 'Sales Order' %}
|
||||
{% if doc.coupon_code %}
|
||||
<tr>
|
||||
<td class="text-left total-discount" colspan="2" style="padding-right: 2rem;">
|
||||
{{ _("Applied Coupon Code") }}
|
||||
</td>
|
||||
<td class="text-right total-discount">
|
||||
<span>
|
||||
{%- for row in frappe.get_all(doctype="Coupon Code",
|
||||
fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
|
||||
<span>{{ row.coupon_code }}</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-left total-discount" colspan="2">
|
||||
{{ _("Savings") }}
|
||||
</td>
|
||||
<td class="text-right total-discount">
|
||||
<span>
|
||||
{% set tot_SO_discount = [] %}
|
||||
{%- for item in doc.items -%}
|
||||
{% if tot_SO_discount.append((((item.price_list_rate * item.qty)
|
||||
* item.discount_percentage) / 100)) %}{% endif %}
|
||||
{% endfor %}
|
||||
{{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<div class="w-100 order-taxes mt-5">
|
||||
<div class="col-4 d-flex border-btm pb-5">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Total Amount") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
<span>
|
||||
{% set total_amount = [] %}
|
||||
{%- for item in doc.items -%}
|
||||
{% if total_amount.append((item.price_list_rate * item.qty)) %}{% endif %}
|
||||
{% endfor %}
|
||||
{{ frappe.utils.fmt_money((total_amount | sum),currency=doc.currency) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-taxes w-100 mt-5">
|
||||
<div class="col-4 d-flex">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Applied Coupon Code") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
<span>
|
||||
{%- for row in frappe.get_all(doctype="Coupon Code",
|
||||
fields=["coupon_code"], filters={ "name":doc.coupon_code}) -%}
|
||||
<span>{{ row.coupon_code }}</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-taxes mt-5">
|
||||
<div class="col-4 d-flex border-btm pb-5">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Savings") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
<span>
|
||||
{% set tot_SO_discount = [] %}
|
||||
{%- for item in doc.items -%}
|
||||
{% if tot_SO_discount.append((((item.price_list_rate * item.qty)
|
||||
* item.discount_percentage) / 100)) %}{% endif %}
|
||||
{% endfor %}
|
||||
{{ frappe.utils.fmt_money((tot_SO_discount | sum),currency=doc.currency) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<th class="text-left item-grand-total" colspan="1">
|
||||
{{ _("Grand Total") }}
|
||||
</th>
|
||||
<th class="text-right item-grand-total totals" colspan="3">
|
||||
{{ doc.get_formatted("grand_total") }}
|
||||
</th>
|
||||
</tr>
|
||||
<div class="w-100 mt-5 order-taxes font-weight-bold">
|
||||
<div class="col-4 d-flex">
|
||||
<div class="item-grand-total col-8">
|
||||
{{ _("Grand Total") }}
|
||||
</div>
|
||||
<div class="item-grand-total col-4 text-right pr-0">
|
||||
{{ doc.get_formatted("grand_total") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,20 +1,22 @@
|
||||
<div class="web-list-item transaction-list-item">
|
||||
<div class="row">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<span class="indicator small {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "gray") }}">
|
||||
{{ doc.name }}</span>
|
||||
<span class="list-item-name font-weight-bold">{{ doc.name }}</span>
|
||||
<div class="small text-muted transaction-time"
|
||||
title="{{ frappe.utils.format_datetime(doc.modified, "medium") }}">
|
||||
{{ frappe.utils.global_date_format(doc.modified) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
<div class="col-sm-3">
|
||||
<span class="indicator-pill {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "gray") }} list-item-status">{{doc.status}}</span>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<div class="small text-muted items-preview ellipsis ellipsis-width">
|
||||
{{ doc.items_preview }}
|
||||
</div>
|
||||
</div>
|
||||
{% if doc.get('grand_total') %}
|
||||
<div class="col-sm-3 text-right bold">
|
||||
<div class="col-sm-3 text-right font-weight-bold item-total">
|
||||
{{ doc.get_formatted("grand_total") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -1,77 +0,0 @@
|
||||
{% extends "templates/web.html" %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#login_btn").click(function() {
|
||||
var me = this;
|
||||
$(this).html("Logging In...").prop("disabled", true);
|
||||
frappe.call({
|
||||
"method": "login",
|
||||
args: {
|
||||
usr: "demo@erpnext.com",
|
||||
pwd: "Demo1234567!!!",
|
||||
lead_email: $("#lead-email").val(),
|
||||
},
|
||||
callback: function(r) {
|
||||
$(me).prop("disabled", false);
|
||||
if(r.exc) {
|
||||
alert("Error, please contact support@erpnext.com");
|
||||
} else {
|
||||
console.log("Logged In");
|
||||
window.location.href = "desk";
|
||||
}
|
||||
}
|
||||
})
|
||||
return false;
|
||||
})
|
||||
.prop("disabled", false);
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
<style>
|
||||
footer, .navbar {
|
||||
display: none;
|
||||
}
|
||||
.page-content {
|
||||
right: 0%;
|
||||
width: 100%;
|
||||
}
|
||||
{% include "templates/styles/card_style.css" %}
|
||||
header, footer {
|
||||
display: none;
|
||||
}
|
||||
html, body {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
{{ _("ERPNext Demo") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class='page-card'>
|
||||
|
||||
<div class='page-card-head'>
|
||||
<span class='indicator blue'>
|
||||
{{ _("ERPNext Demo") }}</span>
|
||||
</div>
|
||||
<!-- <img src="/assets/erpnext/images/erp-icon.svg" style="max-width: 40px; max-height: 40px;"> -->
|
||||
<p>Some functionality is disabled for the demo and the data will be cleared regularly.</p>
|
||||
<div><button type="submit" id="login_btn" class="btn btn-primary btn-sm">Launch Demo</button></div>
|
||||
</div>
|
||||
|
||||
|
||||
<p class='text-muted text-center small' style='margin-top: -20px;'><a href="https://erpnext.com/pricing">Start a free 14-day trial </a>
|
||||
</p>
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
@ -5,149 +5,159 @@
|
||||
{% include "templates/includes/breadcrumbs.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ doc.name }}{% endblock %}
|
||||
{% block title %}
|
||||
{{ doc.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<h2 class="m-0">{{ doc.name }}</h2>
|
||||
<h3 class="m-0">{{ doc.name }}</h3>
|
||||
{% endblock %}
|
||||
|
||||
{% block header_actions %}
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="font-md">{{ _('Actions') }}</span>
|
||||
<b class="caret"></b>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
{% if doc.doctype == 'Purchase Order' %}
|
||||
<a class="dropdown-item" href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}" data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}</a>
|
||||
{% endif %}
|
||||
<a class="dropdown-item" href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}'
|
||||
target="_blank" rel="noopener noreferrer">
|
||||
{{ _("Print") }}
|
||||
</a>
|
||||
</ul>
|
||||
<div class="row">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="font-md">{{ _('Actions') }}</span>
|
||||
<b class="caret"></b>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
{% if doc.doctype == 'Purchase Order' and show_make_pi_button %}
|
||||
<a class="dropdown-item"
|
||||
href="/api/method/erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice_from_portal?purchase_order_name={{ doc.name }}"
|
||||
data-action="make_purchase_invoice">{{ _("Make Purchase Invoice") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="dropdown-item"
|
||||
href='/printview?doctype={{ doc.doctype}}&name={{ doc.name }}&format={{ print_format }}' target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
{{ _("Print") }}
|
||||
</a>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-column col-sm-6">
|
||||
<div class="page-header-actions-block" data-html-block="header-actions">
|
||||
<p>
|
||||
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
|
||||
class="btn btn-primary btn-sm" id="pay-for-order">
|
||||
{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="row transaction-subheading">
|
||||
<div class="col-6">
|
||||
<span class="font-md indicator-pill {{ doc.indicator_color or ("blue" if doc.docstatus==1 else "darkgrey") }}">
|
||||
{% if doc.doctype == "Quotation" and not doc.docstatus %}
|
||||
{{ _("Pending") }}
|
||||
{% else %}
|
||||
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
|
||||
<div>
|
||||
<div class="row transaction-subheading mt-1">
|
||||
<div class="col-6 text-muted small mt-1">
|
||||
{{ frappe.utils.format_date(doc.transaction_date, 'medium') }}
|
||||
{% if doc.valid_till %}
|
||||
<p>
|
||||
{{ _("Valid Till") }}: {{ frappe.utils.format_date(doc.valid_till, 'medium') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 text-muted text-right small pt-3">
|
||||
{{ frappe.utils.format_date(doc.transaction_date, 'medium') }}
|
||||
{% if doc.valid_till %}
|
||||
<p>
|
||||
{{ _("Valid Till") }}: {{ frappe.utils.format_date(doc.valid_till, 'medium') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="small my-3">
|
||||
{%- set party_name = doc.supplier_name if doc.doctype in ['Supplier Quotation', 'Purchase Invoice', 'Purchase Order'] else doc.customer_name %}
|
||||
<b>{{ party_name }}</b>
|
||||
|
||||
{% if doc.contact_display and doc.contact_display != party_name %}
|
||||
<br>
|
||||
{{ doc.contact_display }}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if doc._header %}
|
||||
{{ doc._header }}
|
||||
{% endif %}
|
||||
|
||||
<div class="order-container">
|
||||
<!-- items -->
|
||||
<table class="order-item-table w-100 table">
|
||||
<thead class="order-items order-item-header">
|
||||
<th width="60%">
|
||||
{{ _("Item") }}
|
||||
</th>
|
||||
<th width="20%" class="text-right">
|
||||
{{ _("Quantity") }}
|
||||
</th>
|
||||
<th width="20%" class="text-right">
|
||||
{{ _("Amount") }}
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for d in doc.items %}
|
||||
<tr class="order-items">
|
||||
<td>
|
||||
{{ item_name_and_description(d) }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ d.qty }}
|
||||
{% if d.delivered_qty is defined and d.delivered_qty != None %}
|
||||
<p class="text-muted small">{{ _("Delivered") }} {{ d.delivered_qty }}</p>
|
||||
<div class="row indicator-container mt-2">
|
||||
<div class="col-10">
|
||||
<span class="indicator-pill {{ doc.indicator_color or (" blue" if doc.docstatus==1 else "darkgrey" ) }}">
|
||||
{% if doc.doctype == "Quotation" and not doc.docstatus %}
|
||||
{{ _("Pending") }}
|
||||
{% else %}
|
||||
{{ _(doc.get('indicator_title')) or _(doc.status) or _("Submitted") }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ d.get_formatted("amount") }}
|
||||
<p class="text-muted small">{{ _("Rate:") }} {{ d.get_formatted("rate") }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- taxes -->
|
||||
<div class="order-taxes d-flex justify-content-end">
|
||||
<table>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-right col-2">
|
||||
{%- set party_name = doc.supplier_name if doc.doctype in ['Supplier Quotation', 'Purchase Invoice', 'Purchase
|
||||
Order'] else doc.customer_name %}
|
||||
<b>{{ party_name }}</b>
|
||||
|
||||
{% if doc.contact_display and doc.contact_display != party_name %}
|
||||
<br>
|
||||
{{ doc.contact_display }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if doc._header %}
|
||||
{{ doc._header }}
|
||||
{% endif %}
|
||||
|
||||
<div class="order-container mt-4">
|
||||
<!-- items -->
|
||||
<div class="w-100">
|
||||
<div class="order-items order-item-header mb-1 row text-muted">
|
||||
<span class="col-5">
|
||||
{{ _("Item") }}
|
||||
</span>
|
||||
<span class="d-s-n col-3">
|
||||
{{ _("Quantity") }}
|
||||
</span>
|
||||
<span class="col-2 pl-10">
|
||||
{{ _("Rate") }}
|
||||
</span>
|
||||
<span class="col-2 text-right">
|
||||
{{ _("Amount") }}
|
||||
</span>
|
||||
</div>
|
||||
{% for d in doc.items %}
|
||||
<div class="order-items row align-items-center">
|
||||
<span class="order-item-name col-5 pr-0">
|
||||
{{ item_name_and_description(d) }}
|
||||
</span>
|
||||
|
||||
<span class="d-s-n col-3 pl-10">
|
||||
{{ d.get_formatted("qty") }}
|
||||
</span>
|
||||
<span class="order-rate pl-4 col-2">
|
||||
{{ d.get_formatted("rate") }}
|
||||
</span>
|
||||
<span class="col-2 text-right">
|
||||
{{ d.get_formatted("amount") }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- taxes -->
|
||||
<div class="">
|
||||
{% include "erpnext/templates/includes/order/order_taxes.html" %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if enabled_checkout and ((doc.doctype=="Sales Order" and doc.per_billed <= 0)
|
||||
or (doc.doctype=="Sales Invoice" and doc.outstanding_amount > 0)) %}
|
||||
or (doc.doctype=="Sales Invoice" and doc.outstanding_amount> 0)) %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="form-column col-sm-6 address-title">
|
||||
<strong>Payment</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-collapse">
|
||||
<div class="panel-body text-muted small">
|
||||
<div class="row">
|
||||
<div class="form-column col-sm-6">
|
||||
{% if available_loyalty_points %}
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="form-column col-sm-6 address-title">
|
||||
<strong>Loyalty Points</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="h6">Enter Loyalty Points</div>
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input">
|
||||
<input class="form-control" type="number" min="0" max="{{ available_loyalty_points }}" id="loyalty-point-to-redeem">
|
||||
<input class="form-control" type="number" min="0"
|
||||
max="{{ available_loyalty_points }}" id="loyalty-point-to-redeem">
|
||||
</div>
|
||||
<p class="help-box small text-muted d-none d-sm-block"> Available Points: {{ available_loyalty_points }} </p>
|
||||
<p class="help-box small text-muted d-none d-sm-block"> Available Points: {{
|
||||
available_loyalty_points }} </p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="form-column col-sm-6">
|
||||
<div id="loyalty-points-status" style="text-align: right"></div>
|
||||
<div class="page-header-actions-block" data-html-block="header-actions">
|
||||
<p class="mt-2" style="float: right;">
|
||||
<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
|
||||
class="btn btn-primary btn-sm"
|
||||
id="pay-for-order">
|
||||
{{ _("Pay") }} {{ doc.get_formatted("grand_total") }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -172,17 +182,17 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if doc.terms %}
|
||||
<div class="terms-and-condition text-muted small">
|
||||
<hr><p>{{ doc.terms }}</p>
|
||||
<hr>
|
||||
<p>{{ doc.terms }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script> {% include "templates/pages/order.js" %} </script>
|
||||
<script> {% include "templates/pages/order.js" %}</script>
|
||||
<script>
|
||||
window.doc_info = {
|
||||
customer: '{{doc.customer}}',
|
||||
@ -192,4 +202,4 @@
|
||||
currency: '{{ doc.currency }}'
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
@ -52,6 +52,9 @@ def get_context(context):
|
||||
)
|
||||
context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
|
||||
|
||||
# show Make Purchase Invoice button based on permission
|
||||
context.show_make_pi_button = frappe.has_permission("Purchase Invoice", "create")
|
||||
|
||||
|
||||
def get_attachments(dt, dn):
|
||||
return frappe.get_all(
|
||||
|
@ -785,7 +785,7 @@ Default BOM for {0} not found,Nomenclature par défaut {0} introuvable,
|
||||
Default BOM not found for Item {0} and Project {1},La nomenclature par défaut n'a pas été trouvée pour l'Article {0} et le Projet {1},
|
||||
Default Letter Head,En-Tête de Courrier par Défaut,
|
||||
Default Tax Template,Modèle de Taxes par Défaut,
|
||||
Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,L’Unité de Mesure par Défaut pour l’Article {0} ne peut pas être modifiée directement parce que vous avez déjà fait une (des) transaction (s) avec une autre unité de mesure. Vous devez créer un nouvel article pour utiliser une UDM par défaut différente.,
|
||||
Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.,L’Unité de Mesure par Défaut pour l’Article {0} ne peut pas être modifiée directement parce que vous avez déjà fait une (des) transaction (s) avec une autre unité de mesure. Vous devez créer un nouvel article pour utiliser une UdM par défaut différente.,
|
||||
Default Unit of Measure for Variant '{0}' must be same as in Template '{1}',L’Unité de mesure par défaut pour la variante '{0}' doit être la même que dans le Modèle '{1}',
|
||||
Default settings for buying transactions.,Paramètres par défaut pour les transactions d'achat.,
|
||||
Default settings for selling transactions.,Paramètres par défaut pour les transactions de vente.,
|
||||
@ -838,7 +838,7 @@ Difference Account,Compte d’Écart,
|
||||
"Difference Account must be a Asset/Liability type account, since this Stock Reconciliation is an Opening Entry","Le Compte d’Écart doit être un compte de type Actif / Passif, puisque cette Réconciliation de Stock est une écriture d'à-nouveau",
|
||||
Difference Amount,Écart de Montant,
|
||||
Difference Amount must be zero,L’Écart de Montant doit être égal à zéro,
|
||||
Different UOM for items will lead to incorrect (Total) Net Weight value. Make sure that Net Weight of each item is in the same UOM.,Différentes UDM pour les articles conduira à un Poids Net (Total) incorrect . Assurez-vous que le Poids Net de chaque article a la même unité de mesure .,
|
||||
Different UOM for items will lead to incorrect (Total) Net Weight value. Make sure that Net Weight of each item is in the same UOM.,Différentes UdM pour les articles conduira à un Poids Net (Total) incorrect . Assurez-vous que le Poids Net de chaque article a la même unité de mesure .,
|
||||
Direct Expenses,Charges Directes,
|
||||
Direct Income,Revenu direct,
|
||||
Disable,Désactiver,
|
||||
@ -1409,7 +1409,7 @@ Lab Test,Test de laboratoire,
|
||||
Lab Test Report,Rapport de test de laboratoire,
|
||||
Lab Test Sample,Échantillon de test de laboratoire,
|
||||
Lab Test Template,Modèle de test de laboratoire,
|
||||
Lab Test UOM,UDM de test de laboratoire,
|
||||
Lab Test UOM,UdM de test de laboratoire,
|
||||
Lab Tests and Vital Signs,Tests de laboratoire et signes vitaux,
|
||||
Lab result datetime cannot be before testing datetime,La date et l'heure du résultat de laboratoire ne peuvent pas être avant la date et l'heure du test,
|
||||
Lab testing datetime cannot be before collection datetime,La date et l'heure du test de laboratoire ne peuvent pas être avant la date et l'heure de collecte,
|
||||
@ -2806,7 +2806,7 @@ Stock Received But Not Billed,Stock Reçus Mais Non Facturés,
|
||||
Stock Reports,Rapports de stock,
|
||||
Stock Summary,Résumé du Stock,
|
||||
Stock Transactions,Transactions du Stock,
|
||||
Stock UOM,UDM du Stock,
|
||||
Stock UOM,UdM du Stock,
|
||||
Stock Value,Valeur du Stock,
|
||||
Stock balance in Batch {0} will become negative {1} for Item {2} at Warehouse {3},Solde du stock dans le Lot {0} deviendra négatif {1} pour l'Article {2} à l'Entrepôt {3},
|
||||
Stock cannot be updated against Delivery Note {0},Stock ne peut pas être mis à jour pour le Bon de Livraison {0},
|
||||
@ -3161,9 +3161,9 @@ Trial Period End Date Cannot be before Trial Period Start Date,La date de fin de
|
||||
Trialling,Essai,
|
||||
Type of Business,Type de commerce,
|
||||
Types of activities for Time Logs,Types d'activités pour Journaux de Temps,
|
||||
UOM,UDM,
|
||||
UOM Conversion factor is required in row {0},Facteur de conversion de l'UDM est obligatoire dans la ligne {0},
|
||||
UOM coversion factor required for UOM: {0} in Item: {1},Facteur de coversion UDM requis pour l'UDM : {0} dans l'Article : {1},
|
||||
UOM,UdM,
|
||||
UOM Conversion factor is required in row {0},Facteur de conversion de l'UdM est obligatoire dans la ligne {0},
|
||||
UOM coversion factor required for UOM: {0} in Item: {1},Facteur de coversion UdM requis pour l'UdM : {0} dans l'Article : {1},
|
||||
URL,URL,
|
||||
Unable to find DocType {0},Impossible de trouver le DocType {0},
|
||||
Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually,Impossible de trouver le taux de change pour {0} à {1} pour la date clé {2}. Veuillez créer une entrée de taux de change manuellement,
|
||||
@ -3294,7 +3294,7 @@ Wednesday,Mercredi,
|
||||
Week,Semaine,
|
||||
Weekdays,Jours de la semaine,
|
||||
Weekly,Hebdomadaire,
|
||||
"Weight is mentioned,\nPlease mention ""Weight UOM"" too","Poids est mentionné,\nVeuillez aussi mentionner ""UDM de Poids""",
|
||||
"Weight is mentioned,\nPlease mention ""Weight UOM"" too","Poids est mentionné,\nVeuillez aussi mentionner ""UdM de Poids""",
|
||||
Welcome email sent,Email de bienvenue envoyé,
|
||||
Welcome to ERPNext,Bienvenue sur ERPNext,
|
||||
What do you need help with?,Avec quoi avez vous besoin d'aide ?,
|
||||
@ -4938,12 +4938,15 @@ Is Cumulative,Est cumulatif,
|
||||
Coupon Code Based,Code de coupon basé,
|
||||
Discount on Other Item,Remise sur un autre article,
|
||||
Apply Rule On Other,Appliquer la règle sur autre,
|
||||
Party Information,Informations sur la fête,
|
||||
Party Information,Informations sur le tier,
|
||||
Quantity and Amount,Quantité et montant,
|
||||
Min Qty,Qté Min,
|
||||
Max Qty,Qté Max,
|
||||
Min Amt,Min Amt,
|
||||
Max Amt,Max Amt,
|
||||
Min Amt,Montant Min,
|
||||
Max Amt,Montant Max,
|
||||
"If rate is zero them item will be treated as ""Free Item""",Si le prix est à 0 alors l'article sera traité comme article gratuit
|
||||
Is Recursive,Est récursif
|
||||
"Discounts to be applied in sequential ranges like buy 1 get 1, buy 2 get 2, buy 3 get 3 and so on","La remise sera appliquée séquentiellement telque : acheter 1 => recupérer 1, acheter 2 => recupérer 2, acheter 3 => recupérer 3, etc..."
|
||||
Period Settings,Paramètres de période,
|
||||
Margin,Marge,
|
||||
Margin Type,Type de Marge,
|
||||
@ -5053,7 +5056,7 @@ Quantity and Rate,Quantité et Prix,
|
||||
Received Qty,Qté Reçue,
|
||||
Accepted Qty,Quantité accepté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 (%),
|
||||
Price List Rate (Company Currency),Taux de la Liste de Prix (Devise Société),
|
||||
Rate (Company Currency),Prix (Devise Société),
|
||||
@ -5085,7 +5088,7 @@ Purchase Receipt Detail,Détail du reçu d'achat,
|
||||
Item Weight Details,Détails du poids de l'article,
|
||||
Weight Per Unit,Poids par unité,
|
||||
Total Weight,Poids total,
|
||||
Weight UOM,UDM de Poids,
|
||||
Weight UOM,UdM de Poids,
|
||||
Page Break,Saut de Page,
|
||||
Consider Tax or Charge for,Tenir Compte de la Taxe et des Frais pour,
|
||||
Valuation and Total,Valorisation et Total,
|
||||
@ -5153,7 +5156,7 @@ Advance amount,Montant de l'Avance,
|
||||
Sales Invoice Item,Article de la Facture de Vente,
|
||||
Customer's Item Code,Code de l'Article du Client,
|
||||
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,
|
||||
Rate With Margin,Prix Avec Marge,
|
||||
Discount (%) on Price List Rate with Margin,Remise (%) sur le prix de la Liste de Prix avec la Marge,
|
||||
@ -5501,7 +5504,7 @@ Blanket Order Rate,Prix unitaire de commande avec limites,
|
||||
Returned Qty,Qté Retournée,
|
||||
Purchase Order Item Supplied,Article Fourni depuis la Commande d'Achat,
|
||||
BOM Detail No,N° de Détail de la nomenclature,
|
||||
Stock Uom,UDM du Stock,
|
||||
Stock Uom,UdM du Stock,
|
||||
Raw Material Item Code,Code d’Article de Matière Première,
|
||||
Supplied Qty,Qté Fournie,
|
||||
Purchase Receipt Item Supplied,Articles Fournis du Reçus d’Achat,
|
||||
@ -6149,7 +6152,7 @@ Drug Name / Description,Nom / description du médicament,
|
||||
Dosage,Dosage,
|
||||
Dosage by Time Interval,Dosage par intervalle de temps,
|
||||
Interval,Intervalle,
|
||||
Interval UOM,UDM d'Intervalle,
|
||||
Interval UOM,UdM d'Intervalle,
|
||||
Hour,Heure,
|
||||
Update Schedule,Mettre à Jour le Calendrier,
|
||||
Exercise,Exercice,
|
||||
@ -7023,7 +7026,7 @@ Petrol,Essence,
|
||||
Diesel,Diesel,
|
||||
Natural Gas,Gaz Naturel,
|
||||
Electric,Électrique,
|
||||
Fuel UOM,UDM Carburant,
|
||||
Fuel UOM,UdM Carburant,
|
||||
Last Carbon Check,Dernière Vérification Carbone,
|
||||
Wheels,Roues,
|
||||
Doors,Portes,
|
||||
@ -7182,7 +7185,7 @@ Item to be manufactured or repacked,Article à produire ou à réemballer,
|
||||
Quantity of item obtained after manufacturing / repacking from given quantities of raw materials,Quantité d'article obtenue après production / reconditionnement des quantités données de matières premières,
|
||||
Set rate of sub-assembly item based on BOM,Définir le prix des articles de sous-assemblage en fonction de la nomenclature,
|
||||
Allow Alternative Item,Autoriser un article alternatif,
|
||||
Item UOM,UDM de l'Article,
|
||||
Item UOM,UdM de l'Article,
|
||||
Conversion Rate,Taux de Conversion,
|
||||
Rate Of Materials Based On,Prix des Matériaux Basé sur,
|
||||
With Operations,Avec des Opérations,
|
||||
@ -7926,7 +7929,7 @@ Territory Manager,Responsable Régional,
|
||||
For reference,Pour référence,
|
||||
Territory Targets,Objectifs Régionaux,
|
||||
Set Item Group-wise budgets on this Territory. You can also include seasonality by setting the Distribution.,Définir des budgets par Groupes d'Articles sur ce Territoire. Vous pouvez également inclure de la saisonnalité en définissant la Répartition.,
|
||||
UOM Name,Nom UDM,
|
||||
UOM Name,Nom UdM,
|
||||
Check this to disallow fractions. (for Nos),Cochez cette case pour interdire les fractions. (Pour les numéros),
|
||||
Website Item Group,Groupe d'Articles du Site Web,
|
||||
Cross Listing of Item in multiple groups,Liste Croisée d'Articles dans plusieurs groupes,
|
||||
@ -8198,10 +8201,10 @@ To Package No.,Au N° de Paquet,
|
||||
If more than one package of the same type (for print),Si plus d'un paquet du même type (pour l'impression),
|
||||
Package Weight Details,Détails du Poids du Paquet,
|
||||
The net weight of this package. (calculated automatically as sum of net weight of items),Le poids net de ce paquet. (Calculé automatiquement comme la somme du poids net des articles),
|
||||
Net Weight UOM,UDM Poids Net,
|
||||
Net Weight UOM,UdM Poids Net,
|
||||
Gross Weight,Poids Brut,
|
||||
The gross weight of the package. Usually net weight + packaging material weight. (for print),Le poids brut du colis. Habituellement poids net + poids du matériau d'emballage. (Pour l'impression),
|
||||
Gross Weight UOM,UDM du Poids Brut,
|
||||
Gross Weight UOM,UdM du Poids Brut,
|
||||
Packing Slip Item,Article Emballé,
|
||||
DN Detail,Détail du Bon de Livraison,
|
||||
STO-PICK-.YYYY.-,STO-PICK-.YYYY.-,
|
||||
@ -8215,7 +8218,7 @@ Pick List Item,Élément de la liste de choix,
|
||||
Picked Qty,Quantité choisie,
|
||||
Price List Master,Données de Base des Listes de Prix,
|
||||
Price List Name,Nom de la Liste de Prix,
|
||||
Price Not UOM Dependent,Prix non dépendant de l'UOM,
|
||||
Price Not UOM Dependent,Prix non dépendant de l'UdM,
|
||||
Applicable for Countries,Applicable pour les Pays,
|
||||
Price List Country,Pays de la Liste des Prix,
|
||||
MAT-PRE-.YYYY.-,MAT-PRE-YYYY.-,
|
||||
@ -8294,7 +8297,7 @@ Purchase Receipt No,N° du Reçu d'Achat,
|
||||
Inspection Required,Inspection obligatoire,
|
||||
From BOM,Depuis la nomenclature,
|
||||
For Quantity,Pour la Quantité,
|
||||
As per Stock UOM,Selon UDM du Stock,
|
||||
As per Stock UOM,Selon UdM du Stock,
|
||||
Including items for sub assemblies,Incluant les articles pour des sous-ensembles,
|
||||
Default Source Warehouse,Entrepôt Source par Défaut,
|
||||
Source Warehouse Address,Adresse de l'entrepôt source,
|
||||
@ -8309,7 +8312,7 @@ Total Additional Costs,Total des Coûts Additionnels,
|
||||
Customer or Supplier Details,Détails du Client ou du Fournisseur,
|
||||
Per Transferred,Par transféré,
|
||||
Stock Entry Detail,Détails de l'Écriture de Stock,
|
||||
Basic Rate (as per Stock UOM),Prix 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,
|
||||
Additional Cost,Frais Supplémentaire,
|
||||
Serial No / Batch,N° de Série / Lot,
|
||||
@ -8339,7 +8342,7 @@ Quantity Difference,Différence de Quantité,
|
||||
Amount Difference,Différence de Montant,
|
||||
Item Naming By,Nomenclature d'Article Par,
|
||||
Default Item Group,Groupe d'Éléments par Défaut,
|
||||
Default Stock UOM,UDM par Défaut des Articles,
|
||||
Default Stock UOM,UdM par Défaut des Articles,
|
||||
Sample Retention Warehouse,Entrepôt de stockage des échantillons,
|
||||
Default Valuation Method,Méthode de Valorisation par Défaut,
|
||||
Show Barcode Field,Afficher Champ Code Barre,
|
||||
@ -8353,8 +8356,8 @@ Stock Frozen Upto,Stock Gelé Jusqu'au,
|
||||
Batch Identification,Identification par lots,
|
||||
Use Naming Series,Utiliser la série de noms,
|
||||
Naming Series Prefix,Préfix du nom de série,
|
||||
UOM Category,Catégorie d'unité de mesure (UDM),
|
||||
UOM Conversion Detail,Détails de Conversion de l'UDM,
|
||||
UOM Category,Catégorie d'unité de mesure (UdM),
|
||||
UOM Conversion Detail,Détails de Conversion de l'UdM,
|
||||
Variant Field,Champ de Variante,
|
||||
A logical Warehouse against which stock entries are made.,Un Entrepôt logique dans lequel les entrées en stock sont faites.,
|
||||
Warehouse Detail,Détail de l'Entrepôt,
|
||||
@ -9869,8 +9872,8 @@ Allowed Items,Articles autorisés
|
||||
Party Specific Item,Restriction d'article disponible
|
||||
Restrict Items Based On,Type de critére de restriction
|
||||
Based On Value,critére de restriction
|
||||
Unit of Measure (UOM),Unité de mesure (UDM),
|
||||
Unit Of Measure (UOM),Unité de mesure (UDM),
|
||||
Unit of Measure (UOM),Unité de mesure (UdM),
|
||||
Unit Of Measure (UOM),Unité de mesure (UdM),
|
||||
CRM Settings,Paramètres CRM
|
||||
Do Not Explode,Ne pas décomposer
|
||||
Quick Access, Accés rapides
|
||||
|
Can't render this file because it is too large.
|
@ -9,7 +9,6 @@ from frappe import _
|
||||
def transaction_processing(data, from_doctype, to_doctype):
|
||||
if isinstance(data, str):
|
||||
deserialized_data = json.loads(data)
|
||||
|
||||
else:
|
||||
deserialized_data = data
|
||||
|
||||
@ -30,30 +29,29 @@ def transaction_processing(data, from_doctype, to_doctype):
|
||||
|
||||
|
||||
def job(deserialized_data, from_doctype, to_doctype):
|
||||
failed_history = []
|
||||
i = 0
|
||||
fail_count = 0
|
||||
for d in deserialized_data:
|
||||
failed = []
|
||||
|
||||
try:
|
||||
i += 1
|
||||
doc_name = d.get("name")
|
||||
frappe.db.savepoint("before_creation_state")
|
||||
task(doc_name, from_doctype, to_doctype)
|
||||
|
||||
except Exception as e:
|
||||
frappe.db.rollback(save_point="before_creation_state")
|
||||
failed_history.append(e)
|
||||
failed.append(e)
|
||||
fail_count += 1
|
||||
update_logger(
|
||||
doc_name, e, from_doctype, to_doctype, status="Failed", log_date=str(date.today())
|
||||
doc_name,
|
||||
str(frappe.get_traceback()),
|
||||
from_doctype,
|
||||
to_doctype,
|
||||
status="Failed",
|
||||
log_date=str(date.today()),
|
||||
)
|
||||
if not failed:
|
||||
else:
|
||||
update_logger(
|
||||
doc_name, None, from_doctype, to_doctype, status="Success", log_date=str(date.today())
|
||||
)
|
||||
|
||||
show_job_status(failed_history, deserialized_data, to_doctype)
|
||||
show_job_status(fail_count, len(deserialized_data), to_doctype)
|
||||
|
||||
|
||||
def task(doc_name, from_doctype, to_doctype):
|
||||
@ -94,7 +92,7 @@ def task(doc_name, from_doctype, to_doctype):
|
||||
"Purchase Invoice": purchase_order.make_purchase_invoice,
|
||||
"Purchase Receipt": purchase_order.make_purchase_receipt,
|
||||
},
|
||||
"Purhcase Invoice": {
|
||||
"Purchase Invoice": {
|
||||
"Purchase Receipt": purchase_invoice.make_purchase_receipt,
|
||||
"Payment": payment_entry.get_payment_entry,
|
||||
},
|
||||
@ -150,15 +148,14 @@ def update_logger(doc_name, e, from_doctype, to_doctype, status, log_date=None,
|
||||
log_doc.save()
|
||||
|
||||
|
||||
def show_job_status(failed_history, deserialized_data, to_doctype):
|
||||
if not failed_history:
|
||||
def show_job_status(fail_count, deserialized_data_count, to_doctype):
|
||||
if not fail_count:
|
||||
frappe.msgprint(
|
||||
_("Creation of {0} successful").format(to_doctype),
|
||||
title="Successful",
|
||||
indicator="green",
|
||||
)
|
||||
|
||||
if len(failed_history) != 0 and len(failed_history) < len(deserialized_data):
|
||||
elif fail_count != 0 and fail_count < deserialized_data_count:
|
||||
frappe.msgprint(
|
||||
_(
|
||||
"""Creation of {0} partially successful.
|
||||
@ -167,8 +164,7 @@ def show_job_status(failed_history, deserialized_data, to_doctype):
|
||||
title="Partially successful",
|
||||
indicator="orange",
|
||||
)
|
||||
|
||||
if len(failed_history) == len(deserialized_data):
|
||||
else:
|
||||
frappe.msgprint(
|
||||
_(
|
||||
"""Creation of {0} failed.
|
||||
@ -180,9 +176,7 @@ def show_job_status(failed_history, deserialized_data, to_doctype):
|
||||
|
||||
|
||||
def record_exists(log_doc, doc_name, status):
|
||||
|
||||
record = mark_retrired_transaction(log_doc, doc_name)
|
||||
|
||||
if record and status == "Failed":
|
||||
return False
|
||||
elif record and status == "Success":
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
.time-slot.selected {
|
||||
color: white;
|
||||
background: #5e64ff;
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
.time-slot.selected .text-muted {
|
||||
|
@ -12,8 +12,8 @@
|
||||
<!-- title: Book an appointment -->
|
||||
<div id="select-date-time">
|
||||
<div class="text-center mt-5">
|
||||
<h3>Book an appointment</h3>
|
||||
<p class="lead text-muted" id="lead-text">Select the date and your timezone</p>
|
||||
<h3>{{ _("Book an appointment") }}</h3>
|
||||
<p class="lead text-muted" id="lead-text">{{ _("Select the date and your timezone") }}</p>
|
||||
</div>
|
||||
<div class="row justify-content-center mt-3">
|
||||
<div class="col-md-6 align-self-center ">
|
||||
@ -31,7 +31,7 @@
|
||||
</div>
|
||||
<div class="row justify-content-center mt-3">
|
||||
<div class="col-md-4 mb-3">
|
||||
<button class="btn btn-primary form-control" id="next-button">Next</button>
|
||||
<button class="btn btn-primary form-control" id="next-button">{{ _("Next") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -39,24 +39,24 @@
|
||||
<!--Enter Details-->
|
||||
<div id="enter-details" class="mb-5">
|
||||
<div class="text-center mt-5">
|
||||
<h3>Add details</h3>
|
||||
<p class="lead text-muted">Selected date is <span class="date-span"></span> at <span class="time-span">
|
||||
<h3>{{ _("Add details") }}</h3>
|
||||
<p class="lead text-muted">{{ _("Selected date is") }} <span class="date-span"></span> {{ _("at") }} <span class="time-span">
|
||||
</span></p>
|
||||
</div>
|
||||
<div class="row justify-content-center mt-3">
|
||||
<div class="col-md-4 align-items-center">
|
||||
<form id="customer-form" action='#'>
|
||||
<input class="form-control mt-3" type="text" name="customer_name" id="customer_name" placeholder="Your Name (required)" required>
|
||||
<input class="form-control mt-3" type="text" name="customer_name" id="customer_name" placeholder="{{ _('Your Name (required)') }}" required>
|
||||
<input class="form-control mt-3" type="tel" name="customer_number" id="customer_number" placeholder="+910000000000">
|
||||
<input class="form-control mt-3" type="text" name="customer_skype" id="customer_skype" placeholder="Skype">
|
||||
<input class="form-control mt-3"type="email" name="customer_email" id="customer_email" placeholder="Email Address (required)" required>
|
||||
<input class="form-control mt-3"type="email" name="customer_email" id="customer_email" placeholder="{{ _('Email Address (required)') }}" required>
|
||||
|
||||
<textarea class="form-control mt-3" name="customer_notes" id="customer_notes" cols="30" rows="10"
|
||||
placeholder="Notes"></textarea>
|
||||
placeholder="{{ _('Notes') }}"></textarea>
|
||||
</form>
|
||||
<div class="row mt-3 " id="submit-button-area">
|
||||
<div class="col-md mt-3" style="grid-area: back;"><button class="btn btn-dark form-control" onclick="initialise_select_date()">Go back</button></div>
|
||||
<div class="col-md mt-3" style="grid-area: submit;"><button class="btn btn-primary form-control " onclick="submit()" id="submit-button">Submit</button></div>
|
||||
<div class="col-md mt-3" style="grid-area: back;"><button class="btn btn-dark form-control" onclick="initialise_select_date()">{{ _("Go back") }}</button></div>
|
||||
<div class="col-md mt-3" style="grid-area: submit;"><button class="btn btn-primary form-control " onclick="submit()" id="submit-button">{{ _("Submit") }}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,7 +69,7 @@ function on_date_or_timezone_select() {
|
||||
window.selected_timezone = timezone.value;
|
||||
update_time_slots(date_picker.value, timezone.value);
|
||||
let lead_text = document.getElementById('lead-text');
|
||||
lead_text.innerHTML = "Select Time"
|
||||
lead_text.innerHTML = __("Select Time")
|
||||
}
|
||||
|
||||
async function get_time_slots(date, timezone) {
|
||||
@ -89,7 +89,7 @@ async function update_time_slots(selected_date, selected_timezone) {
|
||||
clear_time_slots();
|
||||
if (window.slots.length <= 0) {
|
||||
let message_div = document.createElement('p');
|
||||
message_div.innerHTML = "There are no slots available on this date";
|
||||
message_div.innerHTML = __("There are no slots available on this date");
|
||||
timeslot_container.appendChild(message_div);
|
||||
return
|
||||
}
|
||||
@ -128,7 +128,7 @@ function get_slot_layout(time) {
|
||||
let start_time_string = moment(time).tz(timezone).format("LT");
|
||||
let end_time = moment(time).tz(timezone).add(window.appointment_settings.appointment_duration, 'minutes');
|
||||
let end_time_string = end_time.format("LT");
|
||||
return `<span style="font-size: 1.2em;">${start_time_string}</span><br><span class="text-muted small">to ${end_time_string}</span>`;
|
||||
return `<span style="font-size: 1.2em;">${start_time_string}</span><br><span class="text-muted small">${__("to") } ${end_time_string}</span>`;
|
||||
}
|
||||
|
||||
function select_time() {
|
||||
@ -227,9 +227,9 @@ async function submit() {
|
||||
},
|
||||
callback: (response)=>{
|
||||
if (response.message.status == "Unverified") {
|
||||
frappe.show_alert("Please check your email to confirm the appointment")
|
||||
frappe.show_alert(__("Please check your email to confirm the appointment"))
|
||||
} else {
|
||||
frappe.show_alert("Appointment Created Successfully");
|
||||
frappe.show_alert(__("Appointment Created Successfully"));
|
||||
}
|
||||
setTimeout(()=>{
|
||||
let redirect_url = "/";
|
||||
@ -239,7 +239,7 @@ async function submit() {
|
||||
window.location.href = redirect_url;},5000)
|
||||
},
|
||||
error: (err)=>{
|
||||
frappe.show_alert("Something went wrong please try again");
|
||||
frappe.show_alert(__("Something went wrong please try again"));
|
||||
button.disabled = false;
|
||||
}
|
||||
});
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
{% if success==True %}
|
||||
<div class="alert alert-success">
|
||||
Your email has been verified and your appointment has been scheduled
|
||||
{{ _("Your email has been verified and your appointment has been scheduled") }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger">
|
||||
Verification failed please check the link
|
||||
{{ _("Verification failed please check the link") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock%}
|
||||
|
Loading…
x
Reference in New Issue
Block a user