Merge branch 'frappe:develop' into currency-exchange-settings
This commit is contained in:
commit
d869b3933b
2
.github/workflows/docker-release.yml
vendored
2
.github/workflows/docker-release.yml
vendored
@ -11,4 +11,4 @@ jobs:
|
||||
- name: curl
|
||||
run: |
|
||||
apk add curl bash
|
||||
curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests
|
||||
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'
|
||||
|
23
.github/workflows/patch.yml
vendored
23
.github/workflows/patch.yml
vendored
@ -86,4 +86,27 @@ jobs:
|
||||
cd ~/frappe-bench/
|
||||
wget https://erpnext.com/files/v10-erpnext.sql.gz
|
||||
bench --site test_site --force restore ~/frappe-bench/v10-erpnext.sql.gz
|
||||
|
||||
git -C "apps/frappe" remote set-url upstream https://github.com/frappe/frappe.git
|
||||
git -C "apps/erpnext" remote set-url upstream https://github.com/frappe/erpnext.git
|
||||
|
||||
for version in $(seq 12 13)
|
||||
do
|
||||
echo "Updating to v$version"
|
||||
branch_name="version-$version"
|
||||
|
||||
git -C "apps/frappe" fetch --depth 1 upstream $branch_name:$branch_name
|
||||
git -C "apps/erpnext" fetch --depth 1 upstream $branch_name:$branch_name
|
||||
|
||||
git -C "apps/frappe" checkout -q -f $branch_name
|
||||
git -C "apps/erpnext" checkout -q -f $branch_name
|
||||
|
||||
bench setup requirements --python
|
||||
bench --site test_site migrate
|
||||
done
|
||||
|
||||
|
||||
echo "Updating to latest version"
|
||||
git -C "apps/frappe" checkout -q -f "${GITHUB_BASE_REF:-${GITHUB_REF##*/}}"
|
||||
git -C "apps/erpnext" checkout -q -f "$GITHUB_SHA"
|
||||
bench --site test_site migrate
|
||||
|
@ -81,7 +81,7 @@ def add_suffix_if_duplicate(account_name, account_number, accounts):
|
||||
def identify_is_group(child):
|
||||
if child.get("is_group"):
|
||||
is_group = child.get("is_group")
|
||||
elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate", "account_number"])):
|
||||
elif len(set(child.keys()) - set(["account_name", "account_type", "root_type", "is_group", "tax_rate", "account_number"])):
|
||||
is_group = 1
|
||||
else:
|
||||
is_group = 0
|
||||
|
@ -58,7 +58,8 @@ class GLEntry(Document):
|
||||
|
||||
# Update outstanding amt on against voucher
|
||||
if (self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice', 'Fees']
|
||||
and self.against_voucher and self.flags.update_outstanding == 'Yes'):
|
||||
and self.against_voucher and self.flags.update_outstanding == 'Yes'
|
||||
and not frappe.flags.is_reverse_depr_entry):
|
||||
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
|
||||
self.against_voucher)
|
||||
|
||||
|
@ -58,7 +58,10 @@ class JournalEntry(AccountsController):
|
||||
if not frappe.flags.in_import:
|
||||
self.validate_total_debit_and_credit()
|
||||
|
||||
self.validate_against_jv()
|
||||
if not frappe.flags.is_reverse_depr_entry:
|
||||
self.validate_against_jv()
|
||||
self.validate_stock_accounts()
|
||||
|
||||
self.validate_reference_doc()
|
||||
if self.docstatus == 0:
|
||||
self.set_against_account()
|
||||
@ -69,7 +72,6 @@ class JournalEntry(AccountsController):
|
||||
self.validate_empty_accounts_table()
|
||||
self.set_account_and_party_balance()
|
||||
self.validate_inter_company_accounts()
|
||||
self.validate_stock_accounts()
|
||||
|
||||
if self.docstatus == 0:
|
||||
self.apply_tax_withholding()
|
||||
|
@ -389,7 +389,7 @@ class PaymentEntry(AccountsController):
|
||||
invoice_paid_amount_map[invoice_key]['outstanding'] = term.outstanding
|
||||
invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)
|
||||
|
||||
for key, allocated_amount in iteritems(invoice_payment_amount_map):
|
||||
for idx, (key, allocated_amount) in enumerate(iteritems(invoice_payment_amount_map), 1):
|
||||
if not invoice_paid_amount_map.get(key):
|
||||
frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1]))
|
||||
|
||||
@ -407,7 +407,7 @@ class PaymentEntry(AccountsController):
|
||||
(allocated_amount - discounted_amt, discounted_amt, allocated_amount, key[1], key[0]))
|
||||
else:
|
||||
if allocated_amount > outstanding:
|
||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
||||
frappe.throw(_('Row #{0}: Cannot allocate more than {1} against payment term {2}').format(idx, outstanding, key[0]))
|
||||
|
||||
if allocated_amount and outstanding:
|
||||
frappe.db.sql("""
|
||||
@ -1053,12 +1053,6 @@ def get_outstanding_reference_documents(args):
|
||||
party_account_currency = get_account_currency(args.get("party_account"))
|
||||
company_currency = frappe.get_cached_value('Company', args.get("company"), "default_currency")
|
||||
|
||||
# Get negative outstanding sales /purchase invoices
|
||||
negative_outstanding_invoices = []
|
||||
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
|
||||
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||
args.get("party_account"), args.get("company"), party_account_currency, company_currency)
|
||||
|
||||
# Get positive outstanding sales /purchase invoices/ Fees
|
||||
condition = ""
|
||||
if args.get("voucher_type") and args.get("voucher_no"):
|
||||
@ -1105,6 +1099,12 @@ def get_outstanding_reference_documents(args):
|
||||
orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"),
|
||||
args.get("party"), args.get("company"), party_account_currency, company_currency, filters=args)
|
||||
|
||||
# Get negative outstanding sales /purchase invoices
|
||||
negative_outstanding_invoices = []
|
||||
if args.get("party_type") not in ["Student", "Employee"] and not args.get("voucher_no"):
|
||||
negative_outstanding_invoices = get_negative_outstanding_invoices(args.get("party_type"), args.get("party"),
|
||||
args.get("party_account"), party_account_currency, company_currency, condition=condition)
|
||||
|
||||
data = negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
|
||||
|
||||
if not data:
|
||||
@ -1137,22 +1137,26 @@ def split_invoices_based_on_payment_terms(outstanding_invoices):
|
||||
'invoice_amount': flt(d.invoice_amount),
|
||||
'outstanding_amount': flt(d.outstanding_amount),
|
||||
'payment_amount': payment_term.payment_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': payment_term.outstanding
|
||||
'payment_term': payment_term.payment_term
|
||||
}))
|
||||
|
||||
outstanding_invoices_after_split = []
|
||||
if invoice_ref_based_on_payment_terms:
|
||||
for idx, ref in invoice_ref_based_on_payment_terms.items():
|
||||
voucher_no = outstanding_invoices[idx]['voucher_no']
|
||||
voucher_type = outstanding_invoices[idx]['voucher_type']
|
||||
voucher_no = ref[0]['voucher_no']
|
||||
voucher_type = ref[0]['voucher_type']
|
||||
|
||||
frappe.msgprint(_("Spliting {} {} into {} rows as per payment terms").format(
|
||||
frappe.msgprint(_("Spliting {} {} into {} row(s) as per Payment Terms").format(
|
||||
voucher_type, voucher_no, len(ref)), alert=True)
|
||||
|
||||
outstanding_invoices.pop(idx - 1)
|
||||
outstanding_invoices += invoice_ref_based_on_payment_terms[idx]
|
||||
outstanding_invoices_after_split += invoice_ref_based_on_payment_terms[idx]
|
||||
|
||||
return outstanding_invoices
|
||||
existing_row = list(filter(lambda x: x.get('voucher_no') == voucher_no, outstanding_invoices))
|
||||
index = outstanding_invoices.index(existing_row[0])
|
||||
outstanding_invoices.pop(index)
|
||||
|
||||
outstanding_invoices_after_split += outstanding_invoices
|
||||
return outstanding_invoices_after_split
|
||||
|
||||
def get_orders_to_be_billed(posting_date, party_type, party,
|
||||
company, party_account_currency, company_currency, cost_center=None, filters=None):
|
||||
@ -1219,7 +1223,7 @@ def get_orders_to_be_billed(posting_date, party_type, party,
|
||||
return order_list
|
||||
|
||||
def get_negative_outstanding_invoices(party_type, party, party_account,
|
||||
company, party_account_currency, company_currency, cost_center=None):
|
||||
party_account_currency, company_currency, cost_center=None, condition=None):
|
||||
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
|
||||
supplier_condition = ""
|
||||
if voucher_type == "Purchase Invoice":
|
||||
@ -1241,19 +1245,21 @@ def get_negative_outstanding_invoices(party_type, party, party_account,
|
||||
`tab{voucher_type}`
|
||||
where
|
||||
{party_type} = %s and {party_account} = %s and docstatus = 1 and
|
||||
company = %s and outstanding_amount < 0
|
||||
outstanding_amount < 0
|
||||
{supplier_condition}
|
||||
{condition}
|
||||
order by
|
||||
posting_date, name
|
||||
""".format(**{
|
||||
"supplier_condition": supplier_condition,
|
||||
"condition": condition,
|
||||
"rounded_total_field": rounded_total_field,
|
||||
"grand_total_field": grand_total_field,
|
||||
"voucher_type": voucher_type,
|
||||
"party_type": scrub(party_type),
|
||||
"party_account": "debit_to" if party_type == "Customer" else "credit_to",
|
||||
"cost_center": cost_center
|
||||
}), (party, party_account, company), as_dict=True)
|
||||
}), (party, party_account), as_dict=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
@ -10,6 +10,9 @@ frappe.ui.form.on('Payment Order', {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_df_property('references', 'cannot_add_rows', true);
|
||||
frm.set_df_property('references', 'cannot_delete_rows', true);
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus == 0) {
|
||||
|
@ -4,9 +4,14 @@
|
||||
frappe.provide("erpnext.accounts");
|
||||
erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationController extends frappe.ui.form.Controller {
|
||||
onload() {
|
||||
var me = this;
|
||||
const default_company = frappe.defaults.get_default('company');
|
||||
this.frm.set_value('company', default_company);
|
||||
|
||||
this.frm.set_query("party_type", function() {
|
||||
this.frm.set_value('party_type', '');
|
||||
this.frm.set_value('party', '');
|
||||
this.frm.set_value('receivable_payable_account', '');
|
||||
|
||||
this.frm.set_query("party_type", () => {
|
||||
return {
|
||||
"filters": {
|
||||
"name": ["in", Object.keys(frappe.boot.party_account_types)],
|
||||
@ -14,44 +19,30 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
}
|
||||
});
|
||||
|
||||
this.frm.set_query('receivable_payable_account', function() {
|
||||
check_mandatory(me.frm);
|
||||
this.frm.set_query('receivable_payable_account', () => {
|
||||
return {
|
||||
filters: {
|
||||
"company": me.frm.doc.company,
|
||||
"company": this.frm.doc.company,
|
||||
"is_group": 0,
|
||||
"account_type": frappe.boot.party_account_types[me.frm.doc.party_type]
|
||||
"account_type": frappe.boot.party_account_types[this.frm.doc.party_type]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
this.frm.set_query('bank_cash_account', function() {
|
||||
check_mandatory(me.frm, true);
|
||||
this.frm.set_query('bank_cash_account', () => {
|
||||
return {
|
||||
filters:[
|
||||
['Account', 'company', '=', me.frm.doc.company],
|
||||
['Account', 'company', '=', this.frm.doc.company],
|
||||
['Account', 'is_group', '=', 0],
|
||||
['Account', 'account_type', 'in', ['Bank', 'Cash']]
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
this.frm.set_value('party_type', '');
|
||||
this.frm.set_value('party', '');
|
||||
this.frm.set_value('receivable_payable_account', '');
|
||||
|
||||
var check_mandatory = (frm, only_company=false) => {
|
||||
var title = __("Mandatory");
|
||||
if (only_company && !frm.doc.company) {
|
||||
frappe.throw({message: __("Please Select a Company First"), title: title});
|
||||
} else if (!frm.doc.company || !frm.doc.party_type) {
|
||||
frappe.throw({message: __("Please Select Both Company and Party Type First"), title: title});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.frm.disable_save();
|
||||
|
||||
this.frm.set_df_property('invoices', 'cannot_delete_rows', true);
|
||||
this.frm.set_df_property('payments', 'cannot_delete_rows', true);
|
||||
this.frm.set_df_property('allocation', 'cannot_delete_rows', true);
|
||||
@ -85,76 +76,92 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
}
|
||||
|
||||
company() {
|
||||
var me = this;
|
||||
this.frm.set_value('party', '');
|
||||
this.frm.set_value('receivable_payable_account', '');
|
||||
me.frm.clear_table("allocation");
|
||||
me.frm.clear_table("invoices");
|
||||
me.frm.clear_table("payments");
|
||||
me.frm.refresh_fields();
|
||||
me.frm.trigger('party');
|
||||
}
|
||||
|
||||
party_type() {
|
||||
this.frm.set_value('party', '');
|
||||
}
|
||||
|
||||
party() {
|
||||
var me = this;
|
||||
if (!me.frm.doc.receivable_payable_account && me.frm.doc.party_type && me.frm.doc.party) {
|
||||
this.frm.set_value('receivable_payable_account', '');
|
||||
this.frm.trigger("clear_child_tables");
|
||||
|
||||
if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) {
|
||||
return frappe.call({
|
||||
method: "erpnext.accounts.party.get_party_account",
|
||||
args: {
|
||||
company: me.frm.doc.company,
|
||||
party_type: me.frm.doc.party_type,
|
||||
party: me.frm.doc.party
|
||||
company: this.frm.doc.company,
|
||||
party_type: this.frm.doc.party_type,
|
||||
party: this.frm.doc.party
|
||||
},
|
||||
callback: function(r) {
|
||||
callback: (r) => {
|
||||
if (!r.exc && r.message) {
|
||||
me.frm.set_value("receivable_payable_account", r.message);
|
||||
this.frm.set_value("receivable_payable_account", r.message);
|
||||
}
|
||||
me.frm.refresh();
|
||||
this.frm.refresh();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
receivable_payable_account() {
|
||||
this.frm.trigger("clear_child_tables");
|
||||
this.frm.refresh();
|
||||
}
|
||||
|
||||
clear_child_tables() {
|
||||
this.frm.clear_table("invoices");
|
||||
this.frm.clear_table("payments");
|
||||
this.frm.clear_table("allocation");
|
||||
this.frm.refresh_fields();
|
||||
}
|
||||
|
||||
get_unreconciled_entries() {
|
||||
var me = this;
|
||||
this.frm.clear_table("allocation");
|
||||
return this.frm.call({
|
||||
doc: me.frm.doc,
|
||||
doc: this.frm.doc,
|
||||
method: 'get_unreconciled_entries',
|
||||
callback: function(r, rt) {
|
||||
if (!(me.frm.doc.payments.length || me.frm.doc.invoices.length)) {
|
||||
frappe.throw({message: __("No invoice and payment records found for this party")});
|
||||
callback: () => {
|
||||
if (!(this.frm.doc.payments.length || this.frm.doc.invoices.length)) {
|
||||
frappe.throw({message: __("No Unreconciled Invoices and Payments found for this party and account")});
|
||||
} else if (!(this.frm.doc.invoices.length)) {
|
||||
frappe.throw({message: __("No Outstanding Invoices found for this party")});
|
||||
} else if (!(this.frm.doc.payments.length)) {
|
||||
frappe.throw({message: __("No Unreconciled Payments found for this party")});
|
||||
}
|
||||
me.frm.refresh();
|
||||
this.frm.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
allocate() {
|
||||
var me = this;
|
||||
let payments = me.frm.fields_dict.payments.grid.get_selected_children();
|
||||
let payments = this.frm.fields_dict.payments.grid.get_selected_children();
|
||||
if (!(payments.length)) {
|
||||
payments = me.frm.doc.payments;
|
||||
payments = this.frm.doc.payments;
|
||||
}
|
||||
let invoices = me.frm.fields_dict.invoices.grid.get_selected_children();
|
||||
let invoices = this.frm.fields_dict.invoices.grid.get_selected_children();
|
||||
if (!(invoices.length)) {
|
||||
invoices = me.frm.doc.invoices;
|
||||
invoices = this.frm.doc.invoices;
|
||||
}
|
||||
return me.frm.call({
|
||||
doc: me.frm.doc,
|
||||
return this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: 'allocate_entries',
|
||||
args: {
|
||||
payments: payments,
|
||||
invoices: invoices
|
||||
},
|
||||
callback: function() {
|
||||
me.frm.refresh();
|
||||
callback: () => {
|
||||
this.frm.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reconcile() {
|
||||
var me = this;
|
||||
var show_dialog = me.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
|
||||
var show_dialog = this.frm.doc.allocation.filter(d => d.difference_amount && !d.difference_account);
|
||||
|
||||
if (show_dialog && show_dialog.length) {
|
||||
|
||||
@ -186,10 +193,10 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
label: __("Difference Account"),
|
||||
fieldname: 'difference_account',
|
||||
reqd: 1,
|
||||
get_query: function() {
|
||||
get_query: () => {
|
||||
return {
|
||||
filters: {
|
||||
company: me.frm.doc.company,
|
||||
company: this.frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
}
|
||||
@ -203,7 +210,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
}]
|
||||
},
|
||||
],
|
||||
primary_action: function() {
|
||||
primary_action: () => {
|
||||
const args = dialog.get_values()["allocation"];
|
||||
|
||||
args.forEach(d => {
|
||||
@ -211,7 +218,7 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
"difference_account", d.difference_account);
|
||||
});
|
||||
|
||||
me.reconcile_payment_entries();
|
||||
this.reconcile_payment_entries();
|
||||
dialog.hide();
|
||||
},
|
||||
primary_action_label: __('Reconcile Entries')
|
||||
@ -237,15 +244,12 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
}
|
||||
|
||||
reconcile_payment_entries() {
|
||||
var me = this;
|
||||
|
||||
return this.frm.call({
|
||||
doc: me.frm.doc,
|
||||
doc: this.frm.doc,
|
||||
method: 'reconcile',
|
||||
callback: function(r, rt) {
|
||||
me.frm.clear_table("allocation");
|
||||
me.frm.refresh_fields();
|
||||
me.frm.refresh();
|
||||
callback: () => {
|
||||
this.frm.clear_table("allocation");
|
||||
this.frm.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -114,6 +114,8 @@ class POSInvoiceMergeLog(Document):
|
||||
def merge_pos_invoice_into(self, invoice, data):
|
||||
items, payments, taxes = [], [], []
|
||||
loyalty_amount_sum, loyalty_points_sum = 0, 0
|
||||
rounding_adjustment, base_rounding_adjustment = 0, 0
|
||||
rounded_total, base_rounded_total = 0, 0
|
||||
for doc in data:
|
||||
map_doc(doc, invoice, table_map={ "doctype": invoice.doctype })
|
||||
|
||||
@ -162,6 +164,11 @@ class POSInvoiceMergeLog(Document):
|
||||
found = True
|
||||
if not found:
|
||||
payments.append(payment)
|
||||
rounding_adjustment += doc.rounding_adjustment
|
||||
rounded_total += doc.rounded_total
|
||||
base_rounding_adjustment += doc.rounding_adjustment
|
||||
base_rounded_total += doc.rounded_total
|
||||
|
||||
|
||||
if loyalty_points_sum:
|
||||
invoice.redeem_loyalty_points = 1
|
||||
@ -171,6 +178,10 @@ class POSInvoiceMergeLog(Document):
|
||||
invoice.set('items', items)
|
||||
invoice.set('payments', payments)
|
||||
invoice.set('taxes', taxes)
|
||||
invoice.set('rounding_adjustment',rounding_adjustment)
|
||||
invoice.set('rounding_adjustment',base_rounding_adjustment)
|
||||
invoice.set('base_rounded_total',base_rounded_total)
|
||||
invoice.set('rounded_total',rounded_total)
|
||||
invoice.additional_discount_percentage = 0
|
||||
invoice.discount_amount = 0.0
|
||||
invoice.taxes_and_charges = None
|
||||
|
@ -2,11 +2,11 @@
|
||||
// For license information, please see license.txt
|
||||
|
||||
let search_fields_datatypes = ['Data', 'Link', 'Dynamic Link', 'Long Text', 'Select', 'Small Text', 'Text', 'Text Editor'];
|
||||
let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "hub_sync_id", "asset_naming_series",
|
||||
let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "asset_naming_series",
|
||||
"default_material_request_type", "valuation_method", "warranty_period", "weight_uom", "batch_number_series",
|
||||
"serial_no_series", "purchase_uom", "customs_tariff_number", "sales_uom", "deferred_revenue_account",
|
||||
"deferred_expense_account", "quality_inspection_template", "route", "slideshow", "website_image_alt", "thumbnail",
|
||||
"web_long_description", "hub_sync_id"]
|
||||
"web_long_description"]
|
||||
|
||||
frappe.ui.form.on('POS Settings', {
|
||||
onload: function(frm) {
|
||||
|
@ -29,6 +29,9 @@ def get_pricing_rules(args, doc=None):
|
||||
pricing_rules = []
|
||||
values = {}
|
||||
|
||||
if not frappe.db.exists('Pricing Rule', {'disable': 0, args.transaction_type: 1}):
|
||||
return
|
||||
|
||||
for apply_on in ['Item Code', 'Item Group', 'Brand']:
|
||||
pricing_rules.extend(_get_pricing_rules(apply_on, args, values))
|
||||
if pricing_rules and not apply_multiple_pricing_rules(pricing_rules):
|
||||
|
@ -37,7 +37,7 @@ from erpnext.assets.doctype.asset.depreciation import (
|
||||
get_disposal_account_and_cost_center,
|
||||
get_gl_entries_on_asset_disposal,
|
||||
get_gl_entries_on_asset_regain,
|
||||
post_depreciation_entries,
|
||||
make_depreciation_entry,
|
||||
)
|
||||
from erpnext.controllers.selling_controller import SellingController
|
||||
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
|
||||
@ -934,6 +934,7 @@ class SalesInvoice(SellingController):
|
||||
asset.db_set("disposal_date", None)
|
||||
|
||||
if asset.calculate_depreciation:
|
||||
self.reverse_depreciation_entry_made_after_sale(asset)
|
||||
self.reset_depreciation_schedule(asset)
|
||||
|
||||
else:
|
||||
@ -997,22 +998,20 @@ class SalesInvoice(SellingController):
|
||||
|
||||
def depreciate_asset(self, asset):
|
||||
asset.flags.ignore_validate_update_after_submit = True
|
||||
asset.prepare_depreciation_data(self.posting_date)
|
||||
asset.prepare_depreciation_data(date_of_sale=self.posting_date)
|
||||
asset.save()
|
||||
|
||||
post_depreciation_entries(self.posting_date)
|
||||
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()
|
||||
asset.prepare_depreciation_data(date_of_return=self.posting_date)
|
||||
|
||||
self.modify_depreciation_schedule_for_asset_repairs(asset)
|
||||
asset.save()
|
||||
|
||||
self.delete_depreciation_entry_made_after_sale(asset)
|
||||
|
||||
def modify_depreciation_schedule_for_asset_repairs(self, asset):
|
||||
asset_repairs = frappe.get_all(
|
||||
'Asset Repair',
|
||||
@ -1026,7 +1025,7 @@ class SalesInvoice(SellingController):
|
||||
asset_repair.modify_depreciation_schedule()
|
||||
asset.prepare_depreciation_data()
|
||||
|
||||
def delete_depreciation_entry_made_after_sale(self, asset):
|
||||
def reverse_depreciation_entry_made_after_sale(self, asset):
|
||||
from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry
|
||||
|
||||
posting_date_of_original_invoice = self.get_posting_date_of_sales_invoice()
|
||||
@ -1041,11 +1040,19 @@ class SalesInvoice(SellingController):
|
||||
row += 1
|
||||
|
||||
if schedule.schedule_date == posting_date_of_original_invoice:
|
||||
if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice):
|
||||
if not self.sale_was_made_on_original_schedule_date(asset, schedule, row, posting_date_of_original_invoice) \
|
||||
or self.sale_happens_in_the_future(posting_date_of_original_invoice):
|
||||
|
||||
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_sales_invoice(self):
|
||||
return frappe.db.get_value('Sales Invoice', self.return_against, 'posting_date')
|
||||
|
||||
@ -1060,6 +1067,12 @@ class SalesInvoice(SellingController):
|
||||
return True
|
||||
return False
|
||||
|
||||
def sale_happens_in_the_future(self, posting_date_of_original_invoice):
|
||||
if posting_date_of_original_invoice > getdate():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def enable_discount_accounting(self):
|
||||
if not hasattr(self, "_enable_discount_accounting"):
|
||||
@ -1975,22 +1988,23 @@ def update_multi_mode_option(doc, pos_profile):
|
||||
def append_payment(payment_mode):
|
||||
payment = doc.append('payments', {})
|
||||
payment.default = payment_mode.default
|
||||
payment.mode_of_payment = payment_mode.parent
|
||||
payment.mode_of_payment = payment_mode.mop
|
||||
payment.account = payment_mode.default_account
|
||||
payment.type = payment_mode.type
|
||||
|
||||
doc.set('payments', [])
|
||||
invalid_modes = []
|
||||
for pos_payment_method in pos_profile.get('payments'):
|
||||
pos_payment_method = pos_payment_method.as_dict()
|
||||
mode_of_payments = [d.mode_of_payment for d in pos_profile.get('payments')]
|
||||
mode_of_payments_info = get_mode_of_payments_info(mode_of_payments, doc.company)
|
||||
|
||||
payment_mode = get_mode_of_payment_info(pos_payment_method.mode_of_payment, doc.company)
|
||||
for row in pos_profile.get('payments'):
|
||||
payment_mode = mode_of_payments_info.get(row.mode_of_payment)
|
||||
if not payment_mode:
|
||||
invalid_modes.append(get_link_to_form("Mode of Payment", pos_payment_method.mode_of_payment))
|
||||
invalid_modes.append(get_link_to_form("Mode of Payment", row.mode_of_payment))
|
||||
continue
|
||||
|
||||
payment_mode[0].default = pos_payment_method.default
|
||||
append_payment(payment_mode[0])
|
||||
payment_mode.default = row.default
|
||||
append_payment(payment_mode)
|
||||
|
||||
if invalid_modes:
|
||||
if invalid_modes == 1:
|
||||
@ -2006,6 +2020,24 @@ def get_all_mode_of_payments(doc):
|
||||
where mpa.parent = mp.name and mpa.company = %(company)s and mp.enabled = 1""",
|
||||
{'company': doc.company}, as_dict=1)
|
||||
|
||||
def get_mode_of_payments_info(mode_of_payments, company):
|
||||
data = frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
mpa.default_account, mpa.parent as mop, mp.type as type
|
||||
from
|
||||
`tabMode of Payment Account` mpa,`tabMode of Payment` mp
|
||||
where
|
||||
mpa.parent = mp.name and
|
||||
mpa.company = %s and
|
||||
mp.enabled = 1 and
|
||||
mp.name in (%s)
|
||||
group by
|
||||
mp.name
|
||||
""", (company, mode_of_payments), as_dict=1)
|
||||
|
||||
return {row.get('mop'): row for row in data}
|
||||
|
||||
def get_mode_of_payment_info(mode_of_payment, company):
|
||||
return frappe.db.sql("""
|
||||
select mpa.default_account, mpa.parent, mp.type as type
|
||||
|
@ -2237,9 +2237,9 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
check_gl_entries(self, si.name, expected_gle, add_days(nowdate(), -1))
|
||||
enable_discount_accounting(enable=0)
|
||||
|
||||
def test_asset_depreciation_on_sale(self):
|
||||
def test_asset_depreciation_on_sale_with_pro_rata(self):
|
||||
"""
|
||||
Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on Sept 30.
|
||||
Tests if an Asset set to depreciate yearly on June 30, that gets sold on Sept 30, creates an additional depreciation entry on its date of sale.
|
||||
"""
|
||||
|
||||
create_asset_data()
|
||||
@ -2252,7 +2252,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
expected_values = [
|
||||
["2020-06-30", 1311.48, 1311.48],
|
||||
["2021-06-30", 20000.0, 21311.48],
|
||||
["2021-09-30", 3966.76, 25278.24]
|
||||
["2021-09-30", 5041.1, 26352.58]
|
||||
]
|
||||
|
||||
for i, schedule in enumerate(asset.schedules):
|
||||
@ -2261,6 +2261,59 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
|
||||
self.assertTrue(schedule.journal_entry)
|
||||
|
||||
def test_asset_depreciation_on_sale_without_pro_rata(self):
|
||||
"""
|
||||
Tests if an Asset set to depreciate yearly on Dec 31, that gets sold on Dec 31 after two years, created an additional depreciation entry on its date of sale.
|
||||
"""
|
||||
|
||||
create_asset_data()
|
||||
asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1,
|
||||
available_for_use_date=getdate("2019-12-31"), total_number_of_depreciations=3,
|
||||
expected_value_after_useful_life=10000, depreciation_start_date=getdate("2020-12-31"), submit=1)
|
||||
|
||||
post_depreciation_entries(getdate("2021-09-30"))
|
||||
|
||||
create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-12-31"))
|
||||
asset.load_from_db()
|
||||
|
||||
expected_values = [
|
||||
["2020-12-31", 30000, 30000],
|
||||
["2021-12-31", 30000, 60000]
|
||||
]
|
||||
|
||||
for i, schedule in enumerate(asset.schedules):
|
||||
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
|
||||
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
|
||||
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
|
||||
self.assertTrue(schedule.journal_entry)
|
||||
|
||||
def test_depreciation_on_return_of_sold_asset(self):
|
||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||
|
||||
create_asset_data()
|
||||
asset = create_asset(item_code="Macbook Pro", calculate_depreciation=1, submit=1)
|
||||
post_depreciation_entries(getdate("2021-09-30"))
|
||||
|
||||
si = create_sales_invoice(item_code="Macbook Pro", asset=asset.name, qty=1, rate=90000, posting_date=getdate("2021-09-30"))
|
||||
return_si = make_return_doc("Sales Invoice", si.name)
|
||||
return_si.submit()
|
||||
asset.load_from_db()
|
||||
|
||||
expected_values = [
|
||||
["2020-06-30", 1311.48, 1311.48, True],
|
||||
["2021-06-30", 20000.0, 21311.48, True],
|
||||
["2022-06-30", 20000.0, 41311.48, False],
|
||||
["2023-06-30", 20000.0, 61311.48, False],
|
||||
["2024-06-30", 20000.0, 81311.48, False],
|
||||
["2025-06-06", 18688.52, 100000.0, False]
|
||||
]
|
||||
|
||||
for i, schedule in enumerate(asset.schedules):
|
||||
self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date)
|
||||
self.assertEqual(expected_values[i][1], schedule.depreciation_amount)
|
||||
self.assertEqual(expected_values[i][2], schedule.accumulated_depreciation_amount)
|
||||
self.assertEqual(schedule.journal_entry, schedule.journal_entry)
|
||||
|
||||
def test_sales_invoice_against_supplier(self):
|
||||
from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (
|
||||
make_customer,
|
||||
|
@ -502,9 +502,11 @@ class Subscription(Document):
|
||||
# Check invoice dates and make sure it doesn't have outstanding invoices
|
||||
return getdate() >= getdate(self.current_invoice_start)
|
||||
|
||||
def is_current_invoice_generated(self):
|
||||
def is_current_invoice_generated(self, _current_start_date=None, _current_end_date=None):
|
||||
invoice = self.get_current_invoice()
|
||||
_current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
|
||||
|
||||
if not (_current_start_date and _current_end_date):
|
||||
_current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
|
||||
|
||||
if invoice and getdate(_current_start_date) <= getdate(invoice.posting_date) <= getdate(_current_end_date):
|
||||
return True
|
||||
@ -523,7 +525,9 @@ class Subscription(Document):
|
||||
if getdate() > getdate(self.current_invoice_end) and self.is_prepaid_to_invoice():
|
||||
self.update_subscription_period(add_days(self.current_invoice_end, 1))
|
||||
|
||||
if not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
|
||||
if not self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \
|
||||
and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
|
||||
|
||||
prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
|
||||
self.generate_invoice(prorate)
|
||||
|
||||
@ -559,14 +563,17 @@ class Subscription(Document):
|
||||
else:
|
||||
self.set_status_grace_period()
|
||||
|
||||
if getdate() > getdate(self.current_invoice_end):
|
||||
self.update_subscription_period(add_days(self.current_invoice_end, 1))
|
||||
|
||||
# Generate invoices periodically even if current invoice are unpaid
|
||||
if self.generate_new_invoices_past_due_date and not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice()
|
||||
or self.is_prepaid_to_invoice()):
|
||||
if self.generate_new_invoices_past_due_date and not \
|
||||
self.is_current_invoice_generated(self.current_invoice_start, self.current_invoice_end) \
|
||||
and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
|
||||
|
||||
prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
|
||||
self.generate_invoice(prorate)
|
||||
|
||||
if getdate() > getdate(self.current_invoice_end):
|
||||
self.update_subscription_period(add_days(self.current_invoice_end, 1))
|
||||
|
||||
@staticmethod
|
||||
def is_paid(invoice):
|
||||
|
@ -58,15 +58,24 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None):
|
||||
pan_no = ''
|
||||
parties = []
|
||||
party_type, party = get_party_details(inv)
|
||||
has_pan_field = frappe.get_meta(party_type).has_field("pan")
|
||||
|
||||
if not tax_withholding_category:
|
||||
tax_withholding_category, pan_no = frappe.db.get_value(party_type, party, ['tax_withholding_category', 'pan'])
|
||||
if has_pan_field:
|
||||
fields = ['tax_withholding_category', 'pan']
|
||||
else:
|
||||
fields = ['tax_withholding_category']
|
||||
|
||||
tax_withholding_details = frappe.db.get_value(party_type, party, fields, as_dict=1)
|
||||
|
||||
tax_withholding_category = tax_withholding_details.get('tax_withholding_category')
|
||||
pan_no = tax_withholding_details.get('pan')
|
||||
|
||||
if not tax_withholding_category:
|
||||
return
|
||||
|
||||
# if tax_withholding_category passed as an argument but not pan_no
|
||||
if not pan_no:
|
||||
if not pan_no and has_pan_field:
|
||||
pan_no = frappe.db.get_value(party_type, party, 'pan')
|
||||
|
||||
# Get others suppliers with the same PAN No
|
||||
@ -174,6 +183,7 @@ def get_lower_deduction_certificate(tax_details, pan_no):
|
||||
ldc_name = frappe.db.get_value('Lower Deduction Certificate',
|
||||
{
|
||||
'pan_no': pan_no,
|
||||
'tax_withholding_category': tax_details.tax_withholding_category,
|
||||
'valid_from': ('>=', tax_details.from_date),
|
||||
'valid_upto': ('<=', tax_details.to_date)
|
||||
}, 'name')
|
||||
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"creation": "2021-10-19 18:06:53.083133",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format Field Template",
|
||||
"document_type": "Purchase Invoice",
|
||||
"field": "taxes",
|
||||
"idx": 0,
|
||||
"modified": "2021-10-19 18:06:53.083133",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Taxes",
|
||||
"owner": "Administrator",
|
||||
"standard": 1,
|
||||
"template": "",
|
||||
"template_file": "templates/print_formats/includes/taxes_and_charges.html"
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"creation": "2021-10-19 17:50:00.152759",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format Field Template",
|
||||
"document_type": "Sales Invoice",
|
||||
"field": "taxes",
|
||||
"idx": 0,
|
||||
"modified": "2021-10-19 18:13:20.894207",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Taxes",
|
||||
"owner": "Administrator",
|
||||
"standard": 1,
|
||||
"template": "",
|
||||
"template_file": "templates/print_formats/includes/taxes_and_charges.html"
|
||||
}
|
@ -114,8 +114,9 @@ def prepare_companywise_opening_balance(asset_data, liability_data, equity_data,
|
||||
|
||||
# opening_value = Aseet - liability - equity
|
||||
for data in [asset_data, liability_data, equity_data]:
|
||||
account_name = get_root_account_name(data[0].root_type, company)
|
||||
opening_value += (get_opening_balance(account_name, data, company) or 0.0)
|
||||
if data:
|
||||
account_name = get_root_account_name(data[0].root_type, company)
|
||||
opening_value += (get_opening_balance(account_name, data, company) or 0.0)
|
||||
|
||||
opening_balance[company] = opening_value
|
||||
|
||||
|
@ -155,6 +155,8 @@ def get_gl_entries(filters, accounting_dimensions):
|
||||
|
||||
if filters.get("group_by") == "Group by Voucher":
|
||||
order_by_statement = "order by posting_date, voucher_type, voucher_no"
|
||||
if filters.get("group_by") == "Group by Account":
|
||||
order_by_statement = "order by account, posting_date, creation"
|
||||
|
||||
if filters.get("include_default_book_entries"):
|
||||
filters['company_fb'] = frappe.db.get_value("Company",
|
||||
|
@ -450,7 +450,8 @@ def update_reference_in_journal_entry(d, journal_entry, do_not_save=False):
|
||||
|
||||
# new row with references
|
||||
new_row = journal_entry.append("accounts")
|
||||
new_row.update(jv_detail.as_dict().copy())
|
||||
|
||||
new_row.update((frappe.copy_doc(jv_detail)).as_dict())
|
||||
|
||||
new_row.set(d["dr_or_cr"], d["allocated_amount"])
|
||||
new_row.set('debit' if d['dr_or_cr'] == 'debit_in_account_currency' else 'credit',
|
||||
|
@ -75,12 +75,12 @@ class Asset(AccountsController):
|
||||
if self.is_existing_asset and self.purchase_invoice:
|
||||
frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
|
||||
|
||||
def prepare_depreciation_data(self, date_of_sale=None):
|
||||
def prepare_depreciation_data(self, date_of_sale=None, date_of_return=None):
|
||||
if self.calculate_depreciation:
|
||||
self.value_after_depreciation = 0
|
||||
self.set_depreciation_rate()
|
||||
self.make_depreciation_schedule(date_of_sale)
|
||||
self.set_accumulated_depreciation(date_of_sale)
|
||||
self.set_accumulated_depreciation(date_of_sale, date_of_return)
|
||||
else:
|
||||
self.finance_books = []
|
||||
self.value_after_depreciation = (flt(self.gross_purchase_amount) -
|
||||
@ -182,7 +182,7 @@ class Asset(AccountsController):
|
||||
d.precision("rate_of_depreciation"))
|
||||
|
||||
def make_depreciation_schedule(self, date_of_sale):
|
||||
if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.schedules:
|
||||
if 'Manual' not in [d.depreciation_method for d in self.finance_books] and not self.get('schedules'):
|
||||
self.schedules = []
|
||||
|
||||
if not self.available_for_use_date:
|
||||
@ -232,13 +232,15 @@ class Asset(AccountsController):
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(d, depreciation_amount,
|
||||
from_date, date_of_sale)
|
||||
|
||||
self.append("schedules", {
|
||||
"schedule_date": date_of_sale,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": d.depreciation_method,
|
||||
"finance_book": d.finance_book,
|
||||
"finance_book_id": d.idx
|
||||
})
|
||||
if depreciation_amount > 0:
|
||||
self.append("schedules", {
|
||||
"schedule_date": date_of_sale,
|
||||
"depreciation_amount": depreciation_amount,
|
||||
"depreciation_method": d.depreciation_method,
|
||||
"finance_book": d.finance_book,
|
||||
"finance_book_id": d.idx
|
||||
})
|
||||
|
||||
break
|
||||
|
||||
# For first row
|
||||
@ -257,11 +259,15 @@ class Asset(AccountsController):
|
||||
self.to_date = add_months(self.available_for_use_date,
|
||||
n * cint(d.frequency_of_depreciation))
|
||||
|
||||
depreciation_amount_without_pro_rata = depreciation_amount
|
||||
|
||||
depreciation_amount, days, months = self.get_pro_rata_amt(d,
|
||||
depreciation_amount, schedule_date, self.to_date)
|
||||
|
||||
monthly_schedule_date = add_months(schedule_date, 1)
|
||||
depreciation_amount = self.get_adjusted_depreciation_amount(depreciation_amount_without_pro_rata,
|
||||
depreciation_amount, d.finance_book)
|
||||
|
||||
monthly_schedule_date = add_months(schedule_date, 1)
|
||||
schedule_date = add_days(schedule_date, days)
|
||||
last_schedule_date = schedule_date
|
||||
|
||||
@ -397,7 +403,28 @@ class Asset(AccountsController):
|
||||
frappe.throw(_("Depreciation Row {0}: Next Depreciation Date cannot be before Available-for-use Date")
|
||||
.format(row.idx))
|
||||
|
||||
def set_accumulated_depreciation(self, date_of_sale=None, ignore_booked_entry = False):
|
||||
# to ensure that final accumulated depreciation amount is accurate
|
||||
def get_adjusted_depreciation_amount(self, depreciation_amount_without_pro_rata, depreciation_amount_for_last_row, finance_book):
|
||||
depreciation_amount_for_first_row = self.get_depreciation_amount_for_first_row(finance_book)
|
||||
|
||||
if depreciation_amount_for_first_row + depreciation_amount_for_last_row != depreciation_amount_without_pro_rata:
|
||||
depreciation_amount_for_last_row = depreciation_amount_without_pro_rata - depreciation_amount_for_first_row
|
||||
|
||||
return depreciation_amount_for_last_row
|
||||
|
||||
def get_depreciation_amount_for_first_row(self, finance_book):
|
||||
if self.has_only_one_finance_book():
|
||||
return self.schedules[0].depreciation_amount
|
||||
else:
|
||||
for schedule in self.schedules:
|
||||
if schedule.finance_book == finance_book:
|
||||
return schedule.depreciation_amount
|
||||
|
||||
def has_only_one_finance_book(self):
|
||||
if len(self.finance_books) == 1:
|
||||
return True
|
||||
|
||||
def set_accumulated_depreciation(self, date_of_sale=None, date_of_return=None, ignore_booked_entry = False):
|
||||
straight_line_idx = [d.idx for d in self.get("schedules") if d.depreciation_method == 'Straight Line']
|
||||
finance_books = []
|
||||
|
||||
@ -414,7 +441,7 @@ class Asset(AccountsController):
|
||||
value_after_depreciation -= flt(depreciation_amount)
|
||||
|
||||
# for the last row, if depreciation method = Straight Line
|
||||
if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale:
|
||||
if straight_line_idx and i == max(straight_line_idx) - 1 and not date_of_sale and not date_of_return:
|
||||
book = self.get('finance_books')[cint(d.finance_book_id) - 1]
|
||||
depreciation_amount += flt(value_after_depreciation -
|
||||
flt(book.expected_value_after_useful_life), d.precision("depreciation_amount"))
|
||||
@ -833,7 +860,7 @@ def get_depreciation_amount(asset, depreciable_value, row):
|
||||
if row.depreciation_method in ("Straight Line", "Manual"):
|
||||
# if the Depreciation Schedule is being prepared for the first time
|
||||
if not asset.flags.increase_in_asset_life:
|
||||
depreciation_amount = (flt(row.value_after_depreciation) -
|
||||
depreciation_amount = (flt(asset.gross_purchase_amount) - flt(asset.opening_accumulated_depreciation) -
|
||||
flt(row.expected_value_after_useful_life)) / depreciation_left
|
||||
|
||||
# if the Depreciation Schedule is being modified after Asset Repair
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,8 @@ frappe.query_reports["Fixed Asset Register"] = {
|
||||
fieldname:"status",
|
||||
label: __("Status"),
|
||||
fieldtype: "Select",
|
||||
options: "In Location\nDisposed",
|
||||
default: 'In Location',
|
||||
reqd: 1
|
||||
options: "\nIn Location\nDisposed",
|
||||
default: 'In Location'
|
||||
},
|
||||
{
|
||||
"fieldname":"filter_based_on",
|
||||
|
@ -45,12 +45,13 @@ def get_conditions(filters):
|
||||
if filters.get('cost_center'):
|
||||
conditions["cost_center"] = filters.get('cost_center')
|
||||
|
||||
# In Store assets are those that are not sold or scrapped
|
||||
operand = 'not in'
|
||||
if status not in 'In Location':
|
||||
operand = 'in'
|
||||
if status:
|
||||
# In Store assets are those that are not sold or scrapped
|
||||
operand = 'not in'
|
||||
if status not in 'In Location':
|
||||
operand = 'in'
|
||||
|
||||
conditions['status'] = (operand, ['Sold', 'Scrapped'])
|
||||
conditions['status'] = (operand, ['Sold', 'Scrapped'])
|
||||
|
||||
return conditions
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"creation": "2021-10-19 18:07:19.253457",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format Field Template",
|
||||
"document_type": "Purchase Order",
|
||||
"field": "taxes",
|
||||
"idx": 0,
|
||||
"modified": "2021-10-19 18:07:19.253457",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Taxes",
|
||||
"owner": "Administrator",
|
||||
"standard": 1,
|
||||
"template": "",
|
||||
"template_file": "templates/print_formats/includes/taxes_and_charges.html"
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"creation": "2021-10-19 18:09:08.103919",
|
||||
"docstatus": 0,
|
||||
"doctype": "Print Format Field Template",
|
||||
"document_type": "Supplier Quotation",
|
||||
"field": "taxes",
|
||||
"idx": 0,
|
||||
"modified": "2021-10-19 18:09:08.103919",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation Taxes",
|
||||
"owner": "Administrator",
|
||||
"standard": 1,
|
||||
"template": "",
|
||||
"template_file": "templates/print_formats/includes/taxes_and_charges.html"
|
||||
}
|
@ -41,10 +41,13 @@ def get_conditions(filters):
|
||||
if filters.get("from_date") and filters.get("to_date"):
|
||||
conditions += " and po.transaction_date between %(from_date)s and %(to_date)s"
|
||||
|
||||
for field in ['company', 'name', 'status']:
|
||||
for field in ['company', 'name']:
|
||||
if filters.get(field):
|
||||
conditions += f" and po.{field} = %({field})s"
|
||||
|
||||
if filters.get('status'):
|
||||
conditions += " and po.status in %(status)s"
|
||||
|
||||
if filters.get('project'):
|
||||
conditions += " and poi.project = %(project)s"
|
||||
|
||||
|
@ -815,6 +815,38 @@ class AccountsController(TransactionBase):
|
||||
if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'):
|
||||
unlink_ref_doc_from_payment_entries(self)
|
||||
|
||||
if self.doctype == "Sales Order":
|
||||
self.unlink_ref_doc_from_po()
|
||||
|
||||
def unlink_ref_doc_from_po(self):
|
||||
so_items = []
|
||||
for item in self.items:
|
||||
so_items.append(item.name)
|
||||
|
||||
linked_po = list(set(frappe.get_all(
|
||||
'Purchase Order Item',
|
||||
filters = {
|
||||
'sales_order': self.name,
|
||||
'sales_order_item': ['in', so_items],
|
||||
'docstatus': ['<', 2]
|
||||
},
|
||||
pluck='parent'
|
||||
)))
|
||||
|
||||
if linked_po:
|
||||
frappe.db.set_value(
|
||||
'Purchase Order Item', {
|
||||
'sales_order': self.name,
|
||||
'sales_order_item': ['in', so_items],
|
||||
'docstatus': ['<', 2]
|
||||
},{
|
||||
'sales_order': None,
|
||||
'sales_order_item': None
|
||||
}
|
||||
)
|
||||
|
||||
frappe.msgprint(_("Purchase Orders {0} are un-linked").format("\n".join(linked_po)))
|
||||
|
||||
def get_tax_map(self):
|
||||
tax_map = {}
|
||||
for tax in self.get('taxes'):
|
||||
@ -1354,8 +1386,8 @@ class AccountsController(TransactionBase):
|
||||
total = 0
|
||||
base_total = 0
|
||||
for d in self.get("payment_schedule"):
|
||||
total += flt(d.payment_amount)
|
||||
base_total += flt(d.base_payment_amount)
|
||||
total += flt(d.payment_amount, d.precision("payment_amount"))
|
||||
base_total += flt(d.base_payment_amount, d.precision("base_payment_amount"))
|
||||
|
||||
base_grand_total = self.get("base_rounded_total") or self.base_grand_total
|
||||
grand_total = self.get("rounded_total") or self.grand_total
|
||||
@ -1371,8 +1403,9 @@ class AccountsController(TransactionBase):
|
||||
else:
|
||||
grand_total -= self.get("total_advance")
|
||||
base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
|
||||
if total != flt(grand_total, self.precision("grand_total")) or \
|
||||
base_total != flt(base_grand_total, self.precision("base_grand_total")):
|
||||
|
||||
if flt(total, self.precision("grand_total")) != flt(grand_total, self.precision("grand_total")) or \
|
||||
flt(base_total, self.precision("base_grand_total")) != flt(base_grand_total, self.precision("base_grand_total")):
|
||||
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
|
||||
|
||||
def is_rounded_total_disabled(self):
|
||||
|
@ -132,7 +132,8 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""select {field} from `tabSupplier`
|
||||
where docstatus < 2
|
||||
and ({key} like %(txt)s
|
||||
or supplier_name like %(txt)s) and disabled=0
|
||||
or supplier_name like %(txt)s) and disabled=0
|
||||
and (on_hold = 0 or (on_hold = 1 and CURDATE() > release_date))
|
||||
{mcond}
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
@ -565,7 +566,7 @@ def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters)
|
||||
|
||||
query_filters.append(['name', query_selector, dimensions])
|
||||
|
||||
output = frappe.get_all(doctype, filters=query_filters)
|
||||
output = frappe.get_list(doctype, filters=query_filters)
|
||||
result = [d.name for d in output]
|
||||
|
||||
return [(d,) for d in set(result)]
|
||||
|
@ -260,7 +260,9 @@ class calculate_taxes_and_totals(object):
|
||||
self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"])
|
||||
|
||||
def calculate_taxes(self):
|
||||
self.doc.rounding_adjustment = 0
|
||||
if not self.doc.get('is_consolidated'):
|
||||
self.doc.rounding_adjustment = 0
|
||||
|
||||
# maintain actual tax rate based on idx
|
||||
actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))]
|
||||
for tax in self.doc.get("taxes") if tax.charge_type == "Actual"])
|
||||
@ -312,7 +314,9 @@ class calculate_taxes_and_totals(object):
|
||||
|
||||
# adjust Discount Amount loss in last tax iteration
|
||||
if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
|
||||
and self.doc.discount_amount and self.doc.apply_discount_on == "Grand Total":
|
||||
and self.doc.discount_amount \
|
||||
and self.doc.apply_discount_on == "Grand Total" \
|
||||
and not self.doc.get('is_consolidated'):
|
||||
self.doc.rounding_adjustment = flt(self.doc.grand_total
|
||||
- flt(self.doc.discount_amount) - tax.total,
|
||||
self.doc.precision("rounding_adjustment"))
|
||||
@ -405,11 +409,16 @@ class calculate_taxes_and_totals(object):
|
||||
self.doc.rounding_adjustment = diff
|
||||
|
||||
def calculate_totals(self):
|
||||
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
|
||||
if self.doc.get("taxes") else flt(self.doc.net_total)
|
||||
if self.doc.get("taxes"):
|
||||
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment)
|
||||
else:
|
||||
self.doc.grand_total = flt(self.doc.net_total)
|
||||
|
||||
self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
|
||||
if self.doc.get("taxes"):
|
||||
self.doc.total_taxes_and_charges = flt(self.doc.grand_total - self.doc.net_total
|
||||
- flt(self.doc.rounding_adjustment), self.doc.precision("total_taxes_and_charges"))
|
||||
else:
|
||||
self.doc.total_taxes_and_charges = 0.0
|
||||
|
||||
self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
|
||||
|
||||
@ -446,19 +455,20 @@ class calculate_taxes_and_totals(object):
|
||||
self.doc.total_net_weight += d.total_weight
|
||||
|
||||
def set_rounded_total(self):
|
||||
if self.doc.meta.get_field("rounded_total"):
|
||||
if self.doc.is_rounded_total_disabled():
|
||||
self.doc.rounded_total = self.doc.base_rounded_total = 0
|
||||
return
|
||||
if not self.doc.get('is_consolidated'):
|
||||
if self.doc.meta.get_field("rounded_total"):
|
||||
if self.doc.is_rounded_total_disabled():
|
||||
self.doc.rounded_total = self.doc.base_rounded_total = 0
|
||||
return
|
||||
|
||||
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
||||
self.doc.currency, self.doc.precision("rounded_total"))
|
||||
self.doc.rounded_total = round_based_on_smallest_currency_fraction(self.doc.grand_total,
|
||||
self.doc.currency, self.doc.precision("rounded_total"))
|
||||
|
||||
#if print_in_rate is set, we would have already calculated rounding adjustment
|
||||
self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
|
||||
self.doc.precision("rounding_adjustment"))
|
||||
#if print_in_rate is set, we would have already calculated rounding adjustment
|
||||
self.doc.rounding_adjustment += flt(self.doc.rounded_total - self.doc.grand_total,
|
||||
self.doc.precision("rounding_adjustment"))
|
||||
|
||||
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
|
||||
self._set_in_company_currency(self.doc, ["rounding_adjustment", "rounded_total"])
|
||||
|
||||
def _cleanup(self):
|
||||
if not self.doc.get('is_consolidated'):
|
||||
|
@ -314,6 +314,8 @@ def make_request_for_quotation(source_name, target_doc=None):
|
||||
@frappe.whitelist()
|
||||
def make_customer(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.opportunity_name = source.name
|
||||
|
||||
if source.opportunity_from == "Lead":
|
||||
target.lead_name = source.party_name
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
"website",
|
||||
"column_break_13",
|
||||
"prospect_owner",
|
||||
"company",
|
||||
"leads_section",
|
||||
"prospect_lead",
|
||||
"address_and_contact_section",
|
||||
@ -153,14 +154,23 @@
|
||||
"fieldname": "address_and_contact_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Address and Contact"
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-27 16:24:42.961967",
|
||||
"migration_hash": "f39fb8f4e18a0e7fd391f0b4b52d8375",
|
||||
"modified": "2021-11-01 13:10:36.759249",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Prospect",
|
||||
"naming_rule": "By fieldname",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
|
@ -60,7 +60,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -144,7 +143,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -226,7 +224,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -308,7 +305,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -390,7 +386,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -472,7 +467,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -554,7 +548,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -636,7 +629,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -718,7 +710,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -800,7 +791,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -882,7 +872,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -964,7 +953,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1046,7 +1034,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1128,7 +1115,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1210,7 +1196,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1292,7 +1277,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1374,7 +1358,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1456,7 +1439,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1538,7 +1520,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1620,7 +1601,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1702,7 +1682,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1784,7 +1763,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1866,7 +1844,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -1948,7 +1925,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2030,7 +2006,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2112,7 +2087,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2194,7 +2168,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2276,7 +2249,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2358,7 +2330,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2440,7 +2411,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2522,7 +2492,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2604,7 +2573,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2686,7 +2654,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2768,7 +2735,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2850,7 +2816,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -2932,7 +2897,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3014,7 +2978,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3098,7 +3061,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3180,7 +3142,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3262,7 +3223,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3344,7 +3304,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3426,7 +3385,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3508,7 +3466,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3590,7 +3547,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3672,7 +3628,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3754,7 +3709,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3836,7 +3790,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -3918,7 +3871,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4000,7 +3952,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4082,7 +4033,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4164,7 +4114,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4246,7 +4195,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4328,7 +4276,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4410,7 +4357,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4492,7 +4438,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4574,7 +4519,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4656,7 +4600,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4738,7 +4681,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4820,7 +4762,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4902,7 +4843,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -4984,7 +4924,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -5066,7 +5005,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
@ -5148,7 +5086,6 @@
|
||||
"standard_rate": 0.0,
|
||||
"stock_uom": "Nos",
|
||||
"supplier_items": [],
|
||||
"synced_with_hub": 0,
|
||||
"taxes": [],
|
||||
"thumbnail": null,
|
||||
"tolerance": 0.0,
|
||||
|
@ -156,6 +156,8 @@ def get_employees_having_an_event_today(event_type):
|
||||
DAY({condition_column}) = DAY(%(today)s)
|
||||
AND
|
||||
MONTH({condition_column}) = MONTH(%(today)s)
|
||||
AND
|
||||
YEAR({condition_column}) < YEAR(%(today)s)
|
||||
AND
|
||||
`status` = 'Active'
|
||||
""",
|
||||
@ -166,6 +168,8 @@ def get_employees_having_an_event_today(event_type):
|
||||
DATE_PART('day', {condition_column}) = date_part('day', %(today)s)
|
||||
AND
|
||||
DATE_PART('month', {condition_column}) = date_part('month', %(today)s)
|
||||
AND
|
||||
DATE_PART('year', {condition_column}) < date_part('year', %(today)s)
|
||||
AND
|
||||
"status" = 'Active'
|
||||
""",
|
||||
|
@ -100,7 +100,7 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-23 20:27:36.027728",
|
||||
"modified": "2021-10-26 20:27:36.027728",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Expense Taxes and Charges",
|
||||
|
@ -1,19 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def enable_hub():
|
||||
hub_settings = frappe.get_doc('Marketplace Settings')
|
||||
hub_settings.register()
|
||||
frappe.db.commit()
|
||||
return hub_settings
|
||||
|
||||
@frappe.whitelist()
|
||||
def sync():
|
||||
hub_settings = frappe.get_doc('Marketplace Settings')
|
||||
hub_settings.sync()
|
@ -1,233 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.desk.form.load import get_attachments
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from six import string_types
|
||||
|
||||
current_user = frappe.session.user
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def register_marketplace(company, company_description):
|
||||
validate_registerer()
|
||||
|
||||
settings = frappe.get_single('Marketplace Settings')
|
||||
message = settings.register_seller(company, company_description)
|
||||
|
||||
if message.get('hub_seller_name'):
|
||||
settings.registered = 1
|
||||
settings.hub_seller_name = message.get('hub_seller_name')
|
||||
settings.save()
|
||||
|
||||
settings.add_hub_user(frappe.session.user)
|
||||
|
||||
return { 'ok': 1 }
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def register_users(user_list):
|
||||
user_list = json.loads(user_list)
|
||||
|
||||
settings = frappe.get_single('Marketplace Settings')
|
||||
|
||||
for user in user_list:
|
||||
settings.add_hub_user(user)
|
||||
|
||||
return user_list
|
||||
|
||||
|
||||
def validate_registerer():
|
||||
if current_user == 'Administrator':
|
||||
frappe.throw(_('Please login as another user to register on Marketplace'))
|
||||
|
||||
valid_roles = ['System Manager', 'Item Manager']
|
||||
|
||||
if not frappe.utils.is_subset(valid_roles, frappe.get_roles()):
|
||||
frappe.throw(_('Only users with {0} role can register on Marketplace').format(', '.join(valid_roles)),
|
||||
frappe.PermissionError)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def call_hub_method(method, params=None):
|
||||
connection = get_hub_connection()
|
||||
|
||||
if isinstance(params, string_types):
|
||||
params = json.loads(params)
|
||||
|
||||
params.update({
|
||||
'cmd': 'hub.hub.api.' + method
|
||||
})
|
||||
|
||||
response = connection.post_request(params)
|
||||
return response
|
||||
|
||||
|
||||
def map_fields(items):
|
||||
field_mappings = get_field_mappings()
|
||||
table_fields = [d.fieldname for d in frappe.get_meta('Item').get_table_fields()]
|
||||
|
||||
hub_seller_name = frappe.db.get_value('Marketplace Settings', 'Marketplace Settings', 'hub_seller_name')
|
||||
|
||||
for item in items:
|
||||
for fieldname in table_fields:
|
||||
item.pop(fieldname, None)
|
||||
|
||||
for mapping in field_mappings:
|
||||
local_fieldname = mapping.get('local_fieldname')
|
||||
remote_fieldname = mapping.get('remote_fieldname')
|
||||
|
||||
value = item.get(local_fieldname)
|
||||
item.pop(local_fieldname, None)
|
||||
item[remote_fieldname] = value
|
||||
|
||||
item['doctype'] = 'Hub Item'
|
||||
item['hub_seller'] = hub_seller_name
|
||||
item.pop('attachments', None)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_valid_items(search_value=''):
|
||||
items = frappe.get_list(
|
||||
'Item',
|
||||
fields=["*"],
|
||||
filters={
|
||||
'disabled': 0,
|
||||
'item_name': ['like', '%' + search_value + '%'],
|
||||
'publish_in_hub': 0
|
||||
},
|
||||
order_by="modified desc"
|
||||
)
|
||||
|
||||
valid_items = filter(lambda x: x.image and x.description, items)
|
||||
|
||||
def prepare_item(item):
|
||||
item.source_type = "local"
|
||||
item.attachments = get_attachments('Item', item.item_code)
|
||||
return item
|
||||
|
||||
valid_items = map(prepare_item, valid_items)
|
||||
|
||||
return valid_items
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_item(ref_doc, data):
|
||||
data = json.loads(data)
|
||||
|
||||
data.update(dict(doctype='Hub Item', name=ref_doc))
|
||||
try:
|
||||
connection = get_hub_connection()
|
||||
connection.update(data)
|
||||
except Exception as e:
|
||||
frappe.log_error(message=e, title='Hub Sync Error')
|
||||
|
||||
@frappe.whitelist()
|
||||
def publish_selected_items(items_to_publish):
|
||||
items_to_publish = json.loads(items_to_publish)
|
||||
items_to_update = []
|
||||
if not len(items_to_publish):
|
||||
frappe.throw(_('No items to publish'))
|
||||
|
||||
for item in items_to_publish:
|
||||
item_code = item.get('item_code')
|
||||
frappe.db.set_value('Item', item_code, 'publish_in_hub', 1)
|
||||
|
||||
hub_dict = {
|
||||
'doctype': 'Hub Tracked Item',
|
||||
'item_code': item_code,
|
||||
'published': 1,
|
||||
'hub_category': item.get('hub_category'),
|
||||
'image_list': item.get('image_list')
|
||||
}
|
||||
frappe.get_doc(hub_dict).insert(ignore_if_duplicate=True)
|
||||
|
||||
items = map_fields(items_to_publish)
|
||||
|
||||
try:
|
||||
item_sync_preprocess(len(items))
|
||||
convert_relative_image_urls_to_absolute(items)
|
||||
|
||||
# TODO: Publish Progress
|
||||
connection = get_hub_connection()
|
||||
connection.insert_many(items)
|
||||
|
||||
item_sync_postprocess()
|
||||
except Exception as e:
|
||||
frappe.log_error(message=e, title='Hub Sync Error')
|
||||
|
||||
@frappe.whitelist()
|
||||
def unpublish_item(item_code, hub_item_name):
|
||||
''' Remove item listing from the marketplace '''
|
||||
|
||||
response = call_hub_method('unpublish_item', {
|
||||
'hub_item_name': hub_item_name
|
||||
})
|
||||
|
||||
if response:
|
||||
frappe.db.set_value('Item', item_code, 'publish_in_hub', 0)
|
||||
frappe.delete_doc('Hub Tracked Item', item_code)
|
||||
else:
|
||||
frappe.throw(_('Unable to update remote activity'))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_unregistered_users():
|
||||
settings = frappe.get_single('Marketplace Settings')
|
||||
registered_users = [user.user for user in settings.users] + ['Administrator', 'Guest']
|
||||
all_users = [user.name for user in frappe.db.get_all('User', filters={'enabled': 1})]
|
||||
unregistered_users = [user for user in all_users if user not in registered_users]
|
||||
return unregistered_users
|
||||
|
||||
|
||||
def item_sync_preprocess(intended_item_publish_count):
|
||||
response = call_hub_method('pre_items_publish', {
|
||||
'intended_item_publish_count': intended_item_publish_count
|
||||
})
|
||||
|
||||
if response:
|
||||
frappe.db.set_value("Marketplace Settings", "Marketplace Settings", "sync_in_progress", 1)
|
||||
return response
|
||||
else:
|
||||
frappe.throw(_('Unable to update remote activity'))
|
||||
|
||||
|
||||
def item_sync_postprocess():
|
||||
response = call_hub_method('post_items_publish', {})
|
||||
if response:
|
||||
frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'last_sync_datetime', frappe.utils.now())
|
||||
else:
|
||||
frappe.throw(_('Unable to update remote activity'))
|
||||
|
||||
frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'sync_in_progress', 0)
|
||||
|
||||
|
||||
def convert_relative_image_urls_to_absolute(items):
|
||||
from six.moves.urllib.parse import urljoin
|
||||
|
||||
for item in items:
|
||||
file_path = item['image']
|
||||
|
||||
if file_path.startswith('/files/'):
|
||||
item['image'] = urljoin(frappe.utils.get_url(), file_path)
|
||||
|
||||
|
||||
def get_hub_connection():
|
||||
settings = frappe.get_single('Marketplace Settings')
|
||||
marketplace_url = settings.marketplace_url
|
||||
hub_user = settings.get_hub_user(frappe.session.user)
|
||||
|
||||
if hub_user:
|
||||
password = hub_user.get_password()
|
||||
hub_connection = FrappeClient(marketplace_url, hub_user.user, password)
|
||||
return hub_connection
|
||||
else:
|
||||
read_only_hub_connection = FrappeClient(marketplace_url)
|
||||
return read_only_hub_connection
|
||||
|
||||
|
||||
def get_field_mappings():
|
||||
return []
|
@ -1,50 +0,0 @@
|
||||
{
|
||||
"condition": "{'name': ('=', frappe.db.get_single_value('Hub Settings', 'company'))}",
|
||||
"creation": "2017-09-07 11:38:43.169065",
|
||||
"docstatus": 0,
|
||||
"doctype": "Data Migration Mapping",
|
||||
"fields": [
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "name",
|
||||
"remote_fieldname": "company_name"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "country",
|
||||
"remote_fieldname": "country"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "\"city\"",
|
||||
"remote_fieldname": "seller_city"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "eval:frappe.local.site",
|
||||
"remote_fieldname": "site_name"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "eval:frappe.session.user",
|
||||
"remote_fieldname": "user"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "company_logo",
|
||||
"remote_fieldname": "company_logo"
|
||||
}
|
||||
],
|
||||
"idx": 2,
|
||||
"local_doctype": "Company",
|
||||
"mapping_name": "Company to Hub Company",
|
||||
"mapping_type": "Push",
|
||||
"migration_id_field": "hub_sync_id",
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Company to Hub Company",
|
||||
"owner": "Administrator",
|
||||
"page_length": 10,
|
||||
"remote_objectname": "Hub Company",
|
||||
"remote_primary_key": "name"
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"condition": "{'reference_doctype': 'Lead', 'user': frappe.db.get_single_value('Hub Settings', 'user'), 'status': 'Pending'}",
|
||||
"creation": "2017-09-20 15:06:40.279930",
|
||||
"docstatus": 0,
|
||||
"doctype": "Data Migration Mapping",
|
||||
"fields": [
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "email_id",
|
||||
"remote_fieldname": "email_id"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "lead_name",
|
||||
"remote_fieldname": "lead_name"
|
||||
}
|
||||
],
|
||||
"idx": 0,
|
||||
"local_doctype": "Lead",
|
||||
"local_primary_key": "email_id",
|
||||
"mapping_name": "Hub Message to Lead",
|
||||
"mapping_type": "Pull",
|
||||
"migration_id_field": "hub_sync_id",
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Hub Message to Lead",
|
||||
"owner": "Administrator",
|
||||
"page_length": 10,
|
||||
"remote_objectname": "Hub Message",
|
||||
"remote_primary_key": "name"
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
{
|
||||
"condition": "{\"publish_in_hub\": 1}",
|
||||
"creation": "2017-09-07 13:27:52.726350",
|
||||
"docstatus": 0,
|
||||
"doctype": "Data Migration Mapping",
|
||||
"fields": [
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "item_code",
|
||||
"remote_fieldname": "item_code"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "item_name",
|
||||
"remote_fieldname": "item_name"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "eval:frappe.db.get_value('Hub Settings' , 'Hub Settings', 'company_email')",
|
||||
"remote_fieldname": "hub_seller"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "image",
|
||||
"remote_fieldname": "image"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "image_list",
|
||||
"remote_fieldname": "image_list"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "item_group",
|
||||
"remote_fieldname": "item_group"
|
||||
},
|
||||
{
|
||||
"is_child_table": 0,
|
||||
"local_fieldname": "hub_category",
|
||||
"remote_fieldname": "hub_category"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"local_doctype": "Item",
|
||||
"mapping_name": "Item to Hub Item",
|
||||
"mapping_type": "Push",
|
||||
"migration_id_field": "hub_sync_id",
|
||||
"modified": "2018-08-19 22:20:25.727581",
|
||||
"modified_by": "Administrator",
|
||||
"name": "Item to Hub Item",
|
||||
"owner": "Administrator",
|
||||
"page_length": 10,
|
||||
"remote_objectname": "Hub Item",
|
||||
"remote_primary_key": "item_code"
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"creation": "2017-09-07 11:39:38.445902",
|
||||
"docstatus": 0,
|
||||
"doctype": "Data Migration Plan",
|
||||
"idx": 1,
|
||||
"mappings": [
|
||||
{
|
||||
"enabled": 1,
|
||||
"mapping": "Item to Hub Item"
|
||||
}
|
||||
],
|
||||
"modified": "2018-08-19 22:20:25.644602",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Hub Sync",
|
||||
"owner": "Administrator",
|
||||
"plan_name": "Hub Sync",
|
||||
"postprocess_method": "erpnext.hub_node.api.item_sync_postprocess"
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Hub Tracked Item', {
|
||||
refresh: function(frm) {
|
||||
|
||||
}
|
||||
});
|
@ -1,210 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:item_code",
|
||||
"beta": 0,
|
||||
"creation": "2018-03-18 09:33:50.267762",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hub_category",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hub Category",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "published",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Published",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "image_list",
|
||||
"fieldtype": "Long Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image List",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-12-10 11:37:35.951019",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Hub Tracked Item",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Item Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 1,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class HubTrackedItem(Document):
|
||||
pass
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestHubTrackedItem(unittest.TestCase):
|
||||
pass
|
@ -1,140 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "",
|
||||
"beta": 0,
|
||||
"creation": "2018-08-31 12:36:45.627531",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hub_user_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hub User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "password",
|
||||
"fieldtype": "Password",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hub Password",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Hub User",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class HubUser(Document):
|
||||
pass
|
@ -1,72 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2018-03-06 04:38:49.891787",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "user",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "User",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Hub Users",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class HubUsers(Document):
|
||||
pass
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Marketplace Settings', {
|
||||
refresh: function(frm) {
|
||||
$('#toolbar-user .marketplace-link').toggle(!frm.doc.disable_marketplace);
|
||||
},
|
||||
});
|
@ -1,410 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 1,
|
||||
"creation": "2018-08-31 15:54:38.795263",
|
||||
"custom": 0,
|
||||
"description": "",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "disable_marketplace",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disable Marketplace",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.disable_marketplace",
|
||||
"fieldname": "marketplace_settings_section",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Marketplace Settings",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "https://hubmarket.org",
|
||||
"fieldname": "marketplace_url",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Marketplace URL (to hide and update label)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "registered",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Registered",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sync_in_progress",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Sync in Progress",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hub_seller_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hub Seller Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "users",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Users",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Hub User",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fieldname": "last_sync_datetime",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Last Sync On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"depends_on": "eval:1",
|
||||
"fieldname": "custom_data",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Custom Data",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2020-09-18 17:26:09.703215",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Hub Node",
|
||||
"name": "Marketplace Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 0,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "All",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
class MarketplaceSettings(Document):
|
||||
|
||||
def register_seller(self, company, company_description):
|
||||
|
||||
country, currency, company_logo = frappe.db.get_value('Company', company,
|
||||
['country', 'default_currency', 'company_logo'])
|
||||
|
||||
company_details = {
|
||||
'company': company,
|
||||
'country': country,
|
||||
'currency': currency,
|
||||
'company_description': company_description,
|
||||
'company_logo': company_logo,
|
||||
'site_name': frappe.utils.get_url()
|
||||
}
|
||||
|
||||
hub_connection = self.get_connection()
|
||||
|
||||
response = hub_connection.post_request({
|
||||
'cmd': 'hub.hub.api.add_hub_seller',
|
||||
'company_details': json.dumps(company_details)
|
||||
})
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def add_hub_user(self, user_email):
|
||||
'''Create a Hub User and User record on hub server
|
||||
and if successfull append it to Hub User table
|
||||
'''
|
||||
|
||||
if not self.registered:
|
||||
return
|
||||
|
||||
hub_connection = self.get_connection()
|
||||
|
||||
first_name, last_name = frappe.db.get_value('User', user_email, ['first_name', 'last_name'])
|
||||
|
||||
hub_user = hub_connection.post_request({
|
||||
'cmd': 'hub.hub.api.add_hub_user',
|
||||
'user_email': user_email,
|
||||
'first_name': first_name,
|
||||
'last_name': last_name,
|
||||
'hub_seller': self.hub_seller_name
|
||||
})
|
||||
|
||||
self.append('users', {
|
||||
'user': hub_user.get('user_email'),
|
||||
'hub_user_name': hub_user.get('hub_user_name'),
|
||||
'password': hub_user.get('password')
|
||||
})
|
||||
|
||||
self.save()
|
||||
|
||||
def get_hub_user(self, user):
|
||||
'''Return the Hub User doc from the `users` table if password is set'''
|
||||
|
||||
filtered_users = list(filter(
|
||||
lambda x: x.user == user and x.password,
|
||||
self.users
|
||||
))
|
||||
|
||||
if filtered_users:
|
||||
return filtered_users[0]
|
||||
|
||||
|
||||
def get_connection(self):
|
||||
return FrappeClient(self.marketplace_url)
|
||||
|
||||
|
||||
def unregister(self):
|
||||
"""Disable the User on hubmarket.org"""
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_marketplace_enabled():
|
||||
if not hasattr(frappe.local, 'is_marketplace_enabled'):
|
||||
frappe.local.is_marketplace_enabled = cint(frappe.db.get_single_value('Marketplace Settings',
|
||||
'disable_marketplace'))
|
||||
|
||||
return frappe.local.is_marketplace_enabled
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestMarketplaceSettings(unittest.TestCase):
|
||||
pass
|
@ -1,148 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
import frappe
|
||||
from frappe.contacts.doctype.contact.contact import get_default_contact
|
||||
from frappe.frappeclient import FrappeClient
|
||||
from frappe.utils import nowdate
|
||||
from frappe.utils.nestedset import get_root_of
|
||||
|
||||
|
||||
def get_list(doctype, start, limit, fields, filters, order_by):
|
||||
pass
|
||||
|
||||
def get_hub_connection():
|
||||
if frappe.db.exists('Data Migration Connector', 'Hub Connector'):
|
||||
hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector')
|
||||
hub_connection = hub_connector.get_connection()
|
||||
return hub_connection.connection
|
||||
|
||||
# read-only connection
|
||||
hub_connection = FrappeClient(frappe.conf.hub_url)
|
||||
return hub_connection
|
||||
|
||||
def make_opportunity(buyer_name, email_id):
|
||||
buyer_name = "HUB-" + buyer_name
|
||||
|
||||
if not frappe.db.exists('Lead', {'email_id': email_id}):
|
||||
lead = frappe.new_doc("Lead")
|
||||
lead.lead_name = buyer_name
|
||||
lead.email_id = email_id
|
||||
lead.save(ignore_permissions=True)
|
||||
|
||||
o = frappe.new_doc("Opportunity")
|
||||
o.opportunity_from = "Lead"
|
||||
o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"]
|
||||
o.save(ignore_permissions=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_rfq_and_send_opportunity(item, supplier):
|
||||
supplier = make_supplier(supplier)
|
||||
contact = make_contact(supplier)
|
||||
item = make_item(item)
|
||||
rfq = make_rfq(item, supplier, contact)
|
||||
status = send_opportunity(contact)
|
||||
|
||||
return {
|
||||
'rfq': rfq,
|
||||
'hub_document_created': status
|
||||
}
|
||||
|
||||
def make_supplier(supplier):
|
||||
# make supplier if not already exists
|
||||
supplier = frappe._dict(json.loads(supplier))
|
||||
|
||||
if not frappe.db.exists('Supplier', {'supplier_name': supplier.supplier_name}):
|
||||
supplier_doc = frappe.get_doc({
|
||||
'doctype': 'Supplier',
|
||||
'supplier_name': supplier.supplier_name,
|
||||
'supplier_group': supplier.supplier_group,
|
||||
'supplier_email': supplier.supplier_email
|
||||
}).insert()
|
||||
else:
|
||||
supplier_doc = frappe.get_doc('Supplier', supplier.supplier_name)
|
||||
|
||||
return supplier_doc
|
||||
|
||||
def make_contact(supplier):
|
||||
contact_name = get_default_contact('Supplier', supplier.supplier_name)
|
||||
# make contact if not already exists
|
||||
if not contact_name:
|
||||
contact = frappe.get_doc({
|
||||
'doctype': 'Contact',
|
||||
'first_name': supplier.supplier_name,
|
||||
'is_primary_contact': 1,
|
||||
'links': [
|
||||
{'link_doctype': 'Supplier', 'link_name': supplier.supplier_name}
|
||||
]
|
||||
})
|
||||
contact.add_email(supplier.supplier_email, is_primary=True)
|
||||
contact.insert()
|
||||
else:
|
||||
contact = frappe.get_doc('Contact', contact_name)
|
||||
|
||||
return contact
|
||||
|
||||
def make_item(item):
|
||||
# make item if not already exists
|
||||
item = frappe._dict(json.loads(item))
|
||||
|
||||
if not frappe.db.exists('Item', {'item_code': item.item_code}):
|
||||
item_doc = frappe.get_doc({
|
||||
'doctype': 'Item',
|
||||
'item_code': item.item_code,
|
||||
'item_group': item.item_group,
|
||||
'is_item_from_hub': 1
|
||||
}).insert()
|
||||
else:
|
||||
item_doc = frappe.get_doc('Item', item.item_code)
|
||||
|
||||
return item_doc
|
||||
|
||||
def make_rfq(item, supplier, contact):
|
||||
# make rfq
|
||||
rfq = frappe.get_doc({
|
||||
'doctype': 'Request for Quotation',
|
||||
'transaction_date': nowdate(),
|
||||
'status': 'Draft',
|
||||
'company': frappe.db.get_single_value('Marketplace Settings', 'company'),
|
||||
'message_for_supplier': 'Please supply the specified items at the best possible rates',
|
||||
'suppliers': [
|
||||
{ 'supplier': supplier.name, 'contact': contact.name }
|
||||
],
|
||||
'items': [
|
||||
{
|
||||
'item_code': item.item_code,
|
||||
'qty': 1,
|
||||
'schedule_date': nowdate(),
|
||||
'warehouse': item.default_warehouse or get_root_of("Warehouse"),
|
||||
'description': item.description,
|
||||
'uom': item.stock_uom
|
||||
}
|
||||
]
|
||||
}).insert()
|
||||
|
||||
rfq.save()
|
||||
rfq.submit()
|
||||
return rfq
|
||||
|
||||
def send_opportunity(contact):
|
||||
# Make Hub Message on Hub with lead data
|
||||
doc = {
|
||||
'doctype': 'Lead',
|
||||
'lead_name': frappe.db.get_single_value('Marketplace Settings', 'company'),
|
||||
'email_id': frappe.db.get_single_value('Marketplace Settings', 'user')
|
||||
}
|
||||
|
||||
args = frappe._dict(dict(
|
||||
doctype='Hub Message',
|
||||
reference_doctype='Lead',
|
||||
data=json.dumps(doc),
|
||||
user=contact.email_id
|
||||
))
|
||||
|
||||
connection = get_hub_connection()
|
||||
response = connection.insert('Hub Message', args)
|
||||
|
||||
return response.ok
|
@ -436,7 +436,7 @@
|
||||
"description": "Item Image (if not slideshow)",
|
||||
"fieldname": "website_image",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Image"
|
||||
"label": "Website Image"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@ -539,7 +539,7 @@
|
||||
"image_field": "image",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-16 12:25:09.081968",
|
||||
"modified": "2021-10-27 14:52:04.500251",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM",
|
||||
|
@ -307,6 +307,9 @@ class BOM(WebsiteGenerator):
|
||||
existing_bom_cost = self.total_cost
|
||||
|
||||
for d in self.get("items"):
|
||||
if not d.item_code:
|
||||
continue
|
||||
|
||||
rate = self.get_rm_rate({
|
||||
"company": self.company,
|
||||
"item_code": d.item_code,
|
||||
@ -599,7 +602,7 @@ class BOM(WebsiteGenerator):
|
||||
for d in self.get('items'):
|
||||
if d.bom_no:
|
||||
self.get_child_exploded_items(d.bom_no, d.stock_qty)
|
||||
else:
|
||||
elif d.item_code:
|
||||
self.add_to_cur_exploded_items(frappe._dict({
|
||||
'item_code' : d.item_code,
|
||||
'item_name' : d.item_name,
|
||||
|
@ -605,7 +605,8 @@ def make_material_request(source_name, target_doc=None):
|
||||
"doctype": "Material Request Item",
|
||||
"field_map": {
|
||||
"required_qty": "qty",
|
||||
"uom": "stock_uom"
|
||||
"uom": "stock_uom",
|
||||
"name": "job_card_item"
|
||||
},
|
||||
"postprocess": update_item,
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ class ProductionPlan(Document):
|
||||
|
||||
if self.total_produced_qty > 0:
|
||||
self.status = "In Process"
|
||||
if self.total_produced_qty >= self.total_planned_qty:
|
||||
if self.check_have_work_orders_completed():
|
||||
self.status = "Completed"
|
||||
|
||||
if self.status != 'Completed':
|
||||
@ -575,6 +575,15 @@ class ProductionPlan(Document):
|
||||
|
||||
self.append("sub_assembly_items", data)
|
||||
|
||||
def check_have_work_orders_completed(self):
|
||||
wo_status = frappe.db.get_list(
|
||||
"Work Order",
|
||||
filters={"production_plan": self.name},
|
||||
fields="status",
|
||||
pluck="status"
|
||||
)
|
||||
return all(s == "Completed" for s in wo_status)
|
||||
|
||||
@frappe.whitelist()
|
||||
def download_raw_materials(doc, warehouses=None):
|
||||
if isinstance(doc, str):
|
||||
|
@ -182,6 +182,7 @@
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "1.0",
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Qty To Manufacture",
|
||||
@ -572,10 +573,11 @@
|
||||
"image_field": "image",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-24 15:14:03.844937",
|
||||
"modified": "2021-10-27 19:21:35.139888",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Work Order",
|
||||
"naming_rule": "By \"Naming Series\" field",
|
||||
"nsm_parent_field": "parent_work_order",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
|
@ -685,9 +685,7 @@ class WorkOrder(Document):
|
||||
if not d.operation:
|
||||
d.operation = operation
|
||||
else:
|
||||
# Attribute a big number (999) to idx for sorting putpose in case idx is NULL
|
||||
# For instance in BOM Explosion Item child table, the items coming from sub assembly items
|
||||
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
|
||||
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or float('inf')):
|
||||
self.append('required_items', {
|
||||
'rate': item.rate,
|
||||
'amount': item.rate * item.qty,
|
||||
|
@ -20,9 +20,8 @@ Agriculture
|
||||
ERPNext Integrations
|
||||
Non Profit
|
||||
Hotels
|
||||
Hub Node
|
||||
Quality Management
|
||||
Communication
|
||||
Loan Management
|
||||
Payroll
|
||||
Telephony
|
||||
Telephony
|
@ -58,11 +58,7 @@ erpnext.patches.v11_0.set_department_for_doctypes
|
||||
erpnext.patches.v11_0.update_allow_transfer_for_manufacture
|
||||
erpnext.patches.v11_0.add_item_group_defaults
|
||||
erpnext.patches.v11_0.add_expense_claim_default_account
|
||||
execute:frappe.delete_doc("Page", "hub")
|
||||
erpnext.patches.v11_0.reset_publish_in_hub_for_all_items
|
||||
erpnext.patches.v11_0.update_hub_url # 2018-08-31 # 2018-09-03
|
||||
erpnext.patches.v11_0.make_job_card
|
||||
erpnext.patches.v10_0.delete_hub_documents # 12-08-2018
|
||||
erpnext.patches.v11_0.add_default_dispatch_notification_template
|
||||
erpnext.patches.v11_0.add_market_segments
|
||||
erpnext.patches.v11_0.add_sales_stages
|
||||
@ -153,7 +149,6 @@ erpnext.patches.v12_0.set_cost_center_in_child_table_of_expense_claim
|
||||
erpnext.patches.v12_0.add_eway_bill_in_delivery_note
|
||||
erpnext.patches.v12_0.set_lead_title_field
|
||||
erpnext.patches.v12_0.set_permission_einvoicing
|
||||
erpnext.patches.v12_0.set_published_in_hub_tracked_item
|
||||
erpnext.patches.v12_0.set_job_offer_applicant_email
|
||||
erpnext.patches.v12_0.create_irs_1099_field_united_states
|
||||
erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
|
||||
@ -308,6 +303,9 @@ erpnext.patches.v13_0.set_status_in_maintenance_schedule_table
|
||||
erpnext.patches.v13_0.add_default_interview_notification_templates
|
||||
erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
|
||||
erpnext.patches.v13_0.requeue_failed_reposts
|
||||
erpnext.patches.v12_0.update_production_plan_status
|
||||
erpnext.patches.v13_0.healthcare_deprecation_warning
|
||||
erpnext.patches.v14_0.delete_healthcare_doctypes
|
||||
erpnext.patches.v13_0.update_category_in_ltds_certificate
|
||||
erpnext.patches.v13_0.create_pan_field_for_india #2
|
||||
erpnext.patches.v14_0.delete_hub_doctypes
|
||||
|
@ -1,19 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
for dt, dn in (("Page", "Hub"), ("DocType", "Hub Settings"), ("DocType", "Hub Category")):
|
||||
frappe.delete_doc(dt, dn, ignore_missing=True)
|
||||
|
||||
if frappe.db.exists("DocType", "Data Migration Plan"):
|
||||
data_migration_plans = frappe.get_all("Data Migration Plan", filters={"module": 'Hub Node'})
|
||||
for plan in data_migration_plans:
|
||||
plan_doc = frappe.get_doc("Data Migration Plan", plan.name)
|
||||
for m in plan_doc.get("mappings"):
|
||||
frappe.delete_doc("Data Migration Mapping", m.mapping, force=True)
|
||||
docs = frappe.get_all("Data Migration Run", filters={"data_migration_plan": plan.name})
|
||||
for doc in docs:
|
||||
frappe.delete_doc("Data Migration Run", doc.name)
|
||||
frappe.delete_doc("Data Migration Plan", plan.name)
|
@ -1,8 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('stock', 'doctype', 'item')
|
||||
frappe.db.sql("""update `tabItem` set publish_in_hub = 0""")
|
@ -1,8 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('hub_node', 'doctype', 'Marketplace Settings')
|
||||
frappe.db.set_value('Marketplace Settings', 'Marketplace Settings', 'marketplace_url', 'https://hubmarket.org')
|
@ -1,14 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("Hub Node", "doctype", "Hub Tracked Item")
|
||||
if not frappe.db.a_row_exists("Hub Tracked Item"):
|
||||
return
|
||||
|
||||
frappe.db.sql('''
|
||||
Update `tabHub Tracked Item`
|
||||
SET published = 1
|
||||
''')
|
31
erpnext/patches/v12_0/update_production_plan_status.py
Normal file
31
erpnext/patches/v12_0/update_production_plan_status.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Copyright (c) 2021, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("manufacturing", "doctype", "production_plan")
|
||||
frappe.db.sql("""
|
||||
UPDATE `tabProduction Plan` ppl
|
||||
SET status = "Completed"
|
||||
WHERE ppl.name IN (
|
||||
SELECT ss.name FROM (
|
||||
SELECT
|
||||
(
|
||||
count(wo.status = "Completed") =
|
||||
count(pp.name)
|
||||
) =
|
||||
(
|
||||
pp.status != "Completed"
|
||||
AND pp.total_produced_qty >= pp.total_planned_qty
|
||||
) AS should_set,
|
||||
pp.name AS name
|
||||
FROM
|
||||
`tabWork Order` wo INNER JOIN`tabProduction Plan` pp
|
||||
ON wo.production_plan = pp.name
|
||||
GROUP BY pp.name
|
||||
HAVING should_set = 1
|
||||
) ss
|
||||
)
|
||||
""")
|
20
erpnext/patches/v13_0/update_category_in_ltds_certificate.py
Normal file
20
erpnext/patches/v13_0/update_category_in_ltds_certificate.py
Normal file
@ -0,0 +1,20 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
company = frappe.get_all('Company', filters = {'country': 'India'})
|
||||
if not company:
|
||||
return
|
||||
|
||||
frappe.reload_doc('regional', 'doctype', 'lower_deduction_certificate')
|
||||
|
||||
ldc = frappe.qb.DocType("Lower Deduction Certificate").as_("ldc")
|
||||
supplier = frappe.qb.DocType("Supplier")
|
||||
|
||||
frappe.qb.update(ldc).inner_join(supplier).on(
|
||||
ldc.supplier == supplier.name
|
||||
).set(
|
||||
ldc.tax_withholding_category, supplier.tax_withholding_category
|
||||
).where(
|
||||
ldc.tax_withholding_category.isnull()
|
||||
).run()
|
10
erpnext/patches/v14_0/delete_hub_doctypes.py
Normal file
10
erpnext/patches/v14_0/delete_hub_doctypes.py
Normal file
@ -0,0 +1,10 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
|
||||
doctypes = frappe.get_all("DocType", {"module": "Hub Node", "custom": 0}, pluck='name')
|
||||
for doctype in doctypes:
|
||||
frappe.delete_doc("DocType", doctype, ignore_missing=True)
|
||||
|
||||
frappe.delete_doc("Module Def", "Hub Node", ignore_missing=True, force=True)
|
@ -1,14 +1,10 @@
|
||||
{
|
||||
"css/erpnext.css": [
|
||||
"public/less/erpnext.less",
|
||||
"public/less/hub.less",
|
||||
"public/scss/call_popup.scss",
|
||||
"public/scss/point-of-sale.scss",
|
||||
"public/scss/hierarchy_chart.scss"
|
||||
],
|
||||
"css/marketplace.css": [
|
||||
"public/less/hub.less"
|
||||
],
|
||||
"js/erpnext-web.min.js": [
|
||||
"public/js/website_utils.js",
|
||||
"public/js/shopping_cart.js"
|
||||
@ -17,9 +13,6 @@
|
||||
"public/scss/website.scss",
|
||||
"public/scss/shopping_cart.scss"
|
||||
],
|
||||
"js/marketplace.min.js": [
|
||||
"public/js/hub/marketplace.js"
|
||||
],
|
||||
"js/erpnext.min.js": [
|
||||
"public/js/conf.js",
|
||||
"public/js/utils.js",
|
||||
@ -41,7 +34,6 @@
|
||||
"public/js/utils/supplier_quick_entry.js",
|
||||
"public/js/education/student_button.html",
|
||||
"public/js/education/assessment_result_tool.html",
|
||||
"public/js/hub/hub_factory.js",
|
||||
"public/js/call_popup/call_popup.js",
|
||||
"public/js/utils/dimension_tree_filter.js",
|
||||
"public/js/telephony.js",
|
||||
|
@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="330"
|
||||
height="345.43808"
|
||||
viewBox="0 0 87.312496 91.397155"
|
||||
version="1.1"
|
||||
id="svg4635"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||
sodipodi:docname="hub-logo.svg"
|
||||
inkscape:export-filename="/home/raghu/Desktop/hub-logo.png"
|
||||
inkscape:export-xdpi="95.878258"
|
||||
inkscape:export-ydpi="95.878258">
|
||||
<defs
|
||||
id="defs4629" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="234.27717"
|
||||
inkscape:cy="167.57445"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1149"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata4632">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(121.51931,-138.66452)">
|
||||
<rect
|
||||
rx="13.229166"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-filename="/home/raghu/Desktop/send/hub-02.png"
|
||||
style="opacity:1;vector-effect:none;fill:#89da29;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
id="rect828"
|
||||
width="87.3125"
|
||||
height="87.3125"
|
||||
x="-121.51931"
|
||||
y="142.74918"
|
||||
ry="13.229166" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:#63c923;fill-opacity:1;stroke:none;stroke-width:3.96875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
clip-path="none"
|
||||
d="m -121.51931,202.96343 v 13.86892 c 0,7.32897 5.90017,13.22917 13.22916,13.22917 h 60.854162 c 6.610072,0 12.056133,-4.80013 13.061216,-11.1187 -43.339761,0.1608 -54.359752,-16.03276 -87.144538,-15.97939 z"
|
||||
id="path830"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;vector-effect:none;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:3.96875;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
clip-path="none"
|
||||
d="m -34.20681,202.96343 c -32.784694,-0.0533 -43.804846,16.14019 -87.14455,15.97939 1.00509,6.31857 6.45115,11.1187 13.06122,11.1187 h 60.854164 c 7.328992,0 13.229166,-5.9002 13.229166,-13.22917 z"
|
||||
id="path832"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path834"
|
||||
d="m -84.351263,175.75725 c -1.30945,0 -2.376091,1.06665 -2.376091,2.37608 v 10.02885 0.001 c 0.06583,4.83083 4.01156,8.73477 8.857351,8.73486 4.8718,5e-5 8.846821,-3.94421 8.871295,-8.81134 v -0.001 -9.95288 c 0,-1.30943 -1.066113,-2.37557 -2.375589,-2.37557 -1.309396,0 -2.376064,1.06614 -2.376064,2.37557 v 9.8888 c 0,2.26045 -1.858169,4.10983 -4.119642,4.10983 -2.263616,0 -4.105699,-1.82766 -4.105699,-4.08968 v -9.90844 c 0,-1.30943 -1.066138,-2.37608 -2.375561,-2.37608 z m -20.887107,0.0925 c -1.30943,0 -2.37609,1.06717 -2.37609,2.3766 v 16.45119 c 0,1.30944 1.06666,2.37609 2.37609,2.37609 1.30945,0 2.37556,-1.06665 2.37556,-2.37609 v -5.97327 h 8.22534 v 5.97327 c 0,1.30944 1.066641,2.37609 2.376091,2.37609 1.309423,0 2.375561,-1.06665 2.375561,-2.37609 v -16.45119 c 0,-1.30943 -1.066138,-2.3766 -2.375561,-2.3766 -1.30945,0 -2.376091,1.06717 -2.376091,2.3766 v 5.72627 h -8.22534 v -5.72627 c 0,-1.30943 -1.06611,-2.3766 -2.37556,-2.3766 z m 41.77419,0 c -0.654712,0 -1.248675,0.26711 -1.678967,0.69764 -0.05368,0.0537 -0.105119,0.10983 -0.153458,0.16846 v 5.3e-4 c -0.04839,0.0586 -0.09427,0.11929 -0.136949,0.18242 v 5.3e-4 c -0.256381,0.37936 -0.406691,0.83617 -0.406691,1.32705 v 16.45119 c 0,0.1635 0.01693,0.3242 0.04858,0.47852 0.09512,0.46331 0.32594,0.87828 0.64852,1.20096 0.161369,0.16136 0.345308,0.29938 0.547264,0.40928 v 0 c 0.134567,0.0732 0.276781,0.13403 0.425318,0.18035 v 0 c 0.148537,0.0463 0.303186,0.0783 0.462518,0.0946 v 0 c 0.07959,0.008 0.160708,0.0124 0.242358,0.0124 h 8.33181 c 0.08747,0 0.167931,-0.0145 0.251142,-0.0238 l 0.09509,0.005 c 0.06019,0.003 0.119407,0.005 0.178779,0.006 h 0.0037 0.0048 c 3.578305,-2e-5 6.487954,-2.90916 6.487981,-6.48747 v -0.001 c -0.0026,-1.51334 -0.578009,-2.9475 -1.540484,-4.10673 0.962448,-1.15892 1.537785,-2.59314 1.540484,-4.10621 v -0.001 c -2.7e-5,-3.57831 -2.909676,-6.48744 -6.487981,-6.48746 h -0.533294 z m 8.865103,4.75062 c 0.96393,0 1.736831,0.77394 1.736831,1.73788 0,0.96394 -0.772901,1.73684 -1.736831,1.73684 v 0 h -0.532792 -5.955718 v -3.47317 h 5.956248 z m 0,8.21552 v 0 c 0.963507,5.3e-4 1.735799,0.77373 1.735799,1.73736 0,0.96394 -0.772901,1.73684 -1.736831,1.73684 h -0.0048 l -0.533294,0.0119 h -5.951591 v -3.4742 h 5.959846 z"
|
||||
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.79375005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#63c923;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:7.93750048;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m -77.859375,138.66406 c -9.653316,0 -18.439915,3.93483 -24.767575,10.28125 a 3.9691471,3.9691471 0 1 0 5.621091,5.60352 c 4.899576,-4.9141 11.6422,-7.94727 19.146484,-7.94727 7.501101,0 14.241542,3.03098 19.140625,7.94141 a 3.9691471,3.9691471 0 1 0 5.619141,-5.60547 c -6.327038,-6.34169 -15.110547,-10.27344 -24.759766,-10.27344 z"
|
||||
id="path838"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 8.2 KiB |
@ -18,7 +18,6 @@ import "./utils/customer_quick_entry";
|
||||
import "./utils/supplier_quick_entry";
|
||||
import "./education/student_button.html";
|
||||
import "./education/assessment_result_tool.html";
|
||||
import "./hub/hub_factory";
|
||||
import "./call_popup/call_popup";
|
||||
import "./utils/dimension_tree_filter";
|
||||
import "./telephony";
|
||||
|
@ -113,15 +113,15 @@ function get_filters() {
|
||||
"fieldname":"period_start_date",
|
||||
"label": __("Start Date"),
|
||||
"fieldtype": "Date",
|
||||
"hidden": 1,
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Date Range'"
|
||||
},
|
||||
{
|
||||
"fieldname":"period_end_date",
|
||||
"label": __("End Date"),
|
||||
"fieldtype": "Date",
|
||||
"hidden": 1,
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Date Range'"
|
||||
},
|
||||
{
|
||||
"fieldname":"from_fiscal_year",
|
||||
@ -129,7 +129,8 @@ function get_filters() {
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
|
||||
},
|
||||
{
|
||||
"fieldname":"to_fiscal_year",
|
||||
@ -137,7 +138,8 @@ function get_filters() {
|
||||
"fieldtype": "Link",
|
||||
"options": "Fiscal Year",
|
||||
"default": frappe.defaults.get_user_default("fiscal_year"),
|
||||
"reqd": 1
|
||||
"reqd": 1,
|
||||
"depends_on": "eval:doc.filter_based_on == 'Fiscal Year'"
|
||||
},
|
||||
{
|
||||
"fieldname": "periodicity",
|
||||
|
@ -1,119 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-page-container">
|
||||
<component :is="current_page.component" :key="current_page.key"></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import Home from './pages/Home.vue';
|
||||
import Search from './pages/Search.vue';
|
||||
import Category from './pages/Category.vue';
|
||||
import SavedItems from './pages/SavedItems.vue';
|
||||
import FeaturedItems from './pages/FeaturedItems.vue';
|
||||
import PublishedItems from './pages/PublishedItems.vue';
|
||||
import Item from './pages/Item.vue';
|
||||
import Seller from './pages/Seller.vue';
|
||||
import SellerItems from './pages/SellerItems.vue';
|
||||
import Publish from './pages/Publish.vue';
|
||||
import Buying from './pages/Buying.vue';
|
||||
import Selling from './pages/Selling.vue';
|
||||
import Messages from './pages/Messages.vue';
|
||||
import NotFound from './pages/NotFound.vue';
|
||||
|
||||
function get_route_map() {
|
||||
const read_only_routes = {
|
||||
'marketplace/home': Home,
|
||||
'marketplace/search/:category/:keyword': Search,
|
||||
'marketplace/category/:category': Category,
|
||||
'marketplace/item/:item': Item,
|
||||
'marketplace/seller/:seller': Seller,
|
||||
'marketplace/seller/:seller/items': SellerItems,
|
||||
'marketplace/not-found': NotFound,
|
||||
}
|
||||
const registered_routes = {
|
||||
'marketplace/profile': Seller,
|
||||
'marketplace/saved-items': SavedItems,
|
||||
'marketplace/featured-items': FeaturedItems,
|
||||
'marketplace/publish': Publish,
|
||||
'marketplace/published-items': PublishedItems,
|
||||
'marketplace/buying': Buying,
|
||||
'marketplace/buying/:item': Messages,
|
||||
'marketplace/selling': Selling,
|
||||
'marketplace/selling/:buyer/:item': Messages
|
||||
}
|
||||
|
||||
return hub.is_seller_registered()
|
||||
? Object.assign({}, read_only_routes, registered_routes)
|
||||
: read_only_routes;
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
current_page: this.get_current_page()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
frappe.route.on('change', () => {
|
||||
if (frappe.get_route()[0] === 'marketplace') {
|
||||
this.set_current_page();
|
||||
frappe.utils.scroll_to(0);
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
set_current_page() {
|
||||
this.current_page = this.get_current_page();
|
||||
},
|
||||
get_current_page() {
|
||||
const route_map = get_route_map();
|
||||
const curr_route = frappe.get_route_str();
|
||||
let route = Object.keys(route_map).filter(route => route == curr_route)[0];
|
||||
if (!route) {
|
||||
// find route by matching it with dynamic part
|
||||
const curr_route_parts = curr_route.split('/');
|
||||
const weighted_routes = Object.keys(route_map)
|
||||
.map(route_str => route_str.split('/'))
|
||||
.filter(route_parts => route_parts.length === curr_route_parts.length)
|
||||
.reduce((obj, route_parts) => {
|
||||
const key = route_parts.join('/');
|
||||
let weight = 0;
|
||||
route_parts.forEach((part, i) => {
|
||||
const curr_route_part = curr_route_parts[i];
|
||||
if (part === curr_route_part || part.includes(':')) {
|
||||
weight += 1;
|
||||
}
|
||||
});
|
||||
|
||||
obj[key] = weight;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
// get the route with the highest weight
|
||||
for (let key in weighted_routes) {
|
||||
const route_weight = weighted_routes[key];
|
||||
if (route_weight === curr_route_parts.length) {
|
||||
route = key;
|
||||
break;
|
||||
} else {
|
||||
route = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!route) {
|
||||
return {
|
||||
key: 'not-found',
|
||||
component: NotFound
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
key: curr_route,
|
||||
component: route_map[route]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,110 +0,0 @@
|
||||
<template>
|
||||
<div ref="sidebar-container">
|
||||
<ul class="list-unstyled hub-sidebar-group" data-nav-buttons>
|
||||
<li class="hub-sidebar-item" v-for="item in items" :key="item.label" v-route="item.route" v-show="item.condition === undefined || item.condition()">
|
||||
{{ item.label }}
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="list-unstyled hub-sidebar-group" data-categories>
|
||||
<li class="hub-sidebar-item is-title bold text-muted">
|
||||
{{ __('Categories') }}
|
||||
</li>
|
||||
<li class="hub-sidebar-item" v-for="category in categories" :key="category.label" v-route="category.route">
|
||||
{{ category.label }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
hub_registered: hub.is_user_registered(),
|
||||
items: [
|
||||
{
|
||||
label: __('Browse'),
|
||||
route: 'marketplace/home'
|
||||
},
|
||||
{
|
||||
label: __('Saved Items'),
|
||||
route: 'marketplace/saved-items',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Your Featured Items'),
|
||||
route: 'marketplace/featured-items',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Your Profile'),
|
||||
route: 'marketplace/profile',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Your Items'),
|
||||
route: 'marketplace/published-items',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Publish Items'),
|
||||
route: 'marketplace/publish',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Selling'),
|
||||
route: 'marketplace/selling',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
{
|
||||
label: __('Buying'),
|
||||
route: 'marketplace/buying',
|
||||
condition: () => this.hub_registered
|
||||
},
|
||||
],
|
||||
categories: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.get_categories()
|
||||
.then(categories => {
|
||||
this.categories = categories.map(c => {
|
||||
return {
|
||||
label: __(c.name),
|
||||
route: 'marketplace/category/' + c.name
|
||||
}
|
||||
});
|
||||
this.categories.unshift({
|
||||
label: __('All'),
|
||||
route: 'marketplace/home'
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
this.update_sidebar_state();
|
||||
});
|
||||
});
|
||||
|
||||
erpnext.hub.on('seller-registered', () => {
|
||||
this.hub_registered = true;
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
this.update_sidebar_state();
|
||||
frappe.route.on('change', () => this.update_sidebar_state());
|
||||
},
|
||||
methods: {
|
||||
get_categories() {
|
||||
return hub.call('get_categories');
|
||||
},
|
||||
update_sidebar_state() {
|
||||
const container = $(this.$refs['sidebar-container']);
|
||||
const route = frappe.get_route();
|
||||
const route_str = route.join('/');
|
||||
const part_route_str = route.slice(0, 2).join('/');
|
||||
const $sidebar_item = container.find(`[data-route="${route_str}"], [data-route="${part_route_str}"]`);
|
||||
|
||||
const $siblings = container.find('[data-route]');
|
||||
$siblings.removeClass('active').addClass('text-muted');
|
||||
$sidebar_item.addClass('active').removeClass('text-muted');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="comment-input"></div>
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<span class="text-muted">{{ __('Ctrl + Enter to submit') }}</span>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<button class="btn btn-primary btn-xs" @click="submit_input">{{ __('Submit') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
this.make_input();
|
||||
},
|
||||
methods: {
|
||||
make_input() {
|
||||
this.message_input = frappe.ui.form.make_control({
|
||||
parent: this.$refs['comment-input'],
|
||||
on_submit: (message) => {
|
||||
this.message_input.reset();
|
||||
this.$emit('change', message);
|
||||
},
|
||||
only_input: true,
|
||||
no_wrapper: true
|
||||
});
|
||||
},
|
||||
submit_input() {
|
||||
if (!this.message_input) return;
|
||||
const value = this.message_input.get_value();
|
||||
if (!value) return;
|
||||
this.message_input.submit();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<p class="text-muted" v-if="!Array.isArray(this.header_items)" v-html="header_items"></p>
|
||||
<p class="text-muted" v-else>
|
||||
<span v-for="(header_item , index) in header_items" :key="index">
|
||||
<span v-if="index" v-html="spacer"></span>
|
||||
<span v-if="typeof(header_item) == 'string'" v-html="header_item"></span>
|
||||
<a v-else-if="typeof(header_item) == 'object'" @click="header_item.on_click(header_item.value)" v-html="header_item.value"></a>
|
||||
</span>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
const spacer = '<span aria-hidden="true"> · </span>';
|
||||
|
||||
export default {
|
||||
name: 'detail-header-item',
|
||||
props: ['value'],
|
||||
data() {
|
||||
return {
|
||||
header_items: this.value,
|
||||
spacer: spacer
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-item-container">
|
||||
<div class="row visible-xs">
|
||||
<div class="col-xs-12 margin-bottom">
|
||||
<button class="btn btn-xs btn-default" data-route="marketplace/home">{{ back_to_home_text }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="show_skeleton" class="row margin-bottom">
|
||||
<div class="col-md-3">
|
||||
<div class="hub-item-skeleton-image"></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2 class="hub-skeleton" style="width: 75%;">Name</h2>
|
||||
<div class="text-muted">
|
||||
<p class="hub-skeleton" style="width: 35%;">Details</p>
|
||||
<p class="hub-skeleton" style="width: 50%;">Ratings</p>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="hub-item-description">
|
||||
<p class="hub-skeleton">Desc</p>
|
||||
<p class="hub-skeleton" style="width: 85%;">Desc</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="row margin-bottom">
|
||||
<div class="col-md-3">
|
||||
<div class="hub-item-image">
|
||||
<base-image :src="image" :alt="title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8" style='padding-left: 30px;'>
|
||||
<h2>{{ title }}</h2>
|
||||
<div class="text-muted">
|
||||
<slot name="detail-header-item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="menu_items && menu_items.length" class="col-md-1">
|
||||
<div class="dropdown pull-right hub-item-dropdown">
|
||||
<a class="dropdown-toggle btn btn-xs btn-default" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-right" role="menu">
|
||||
<li v-for="menu_item in menu_items"
|
||||
v-if="menu_item.condition"
|
||||
:key="menu_item.label"
|
||||
>
|
||||
<a @click="menu_item.action">{{ menu_item.label }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="section in sections" class="row hub-item-description margin-bottom"
|
||||
:key="section.title"
|
||||
>
|
||||
<h6 class="col-md-12 margin-top">
|
||||
<b class="text-muted">{{ section.title }}</b>
|
||||
</h6>
|
||||
<p class="col-md-12" v-html="section.content">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'detail-view',
|
||||
props: ['title', 'image', 'sections', 'show_skeleton', 'menu_items'],
|
||||
data() {
|
||||
return {
|
||||
back_to_home_text: __('Back to Home')
|
||||
}
|
||||
},
|
||||
computed: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<div class="empty-state flex flex-column"
|
||||
:class="{ 'bordered': bordered, 'align-center': centered, 'justify-center': centered }"
|
||||
:style="{ height: height + 'px' }"
|
||||
>
|
||||
<p class="text-muted" v-html="message" ></p>
|
||||
<p v-if="action">
|
||||
<button class="btn btn-default btn-xs"
|
||||
@click="action.on_click"
|
||||
>
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'empty-state',
|
||||
props: {
|
||||
message: String,
|
||||
bordered: Boolean,
|
||||
height: Number,
|
||||
action: Object,
|
||||
centered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import "../../../../../../frappe/frappe/public/less/variables.less";
|
||||
|
||||
.empty-state {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.empty-state.bordered {
|
||||
border-radius: 4px;
|
||||
border: 1px solid @border-color;
|
||||
border-style: dashed;
|
||||
|
||||
// bad, due to item card column layout, that is inner 15px margin
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-image">
|
||||
<img :src="src" :alt="alt" v-show="!is_loading && !is_broken"/>
|
||||
<div class="hub-image-loading" v-if="is_loading">
|
||||
<span class="octicon octicon-cloud-download"></span>
|
||||
</div>
|
||||
<div class="hub-image-broken" v-if="is_broken">
|
||||
<span class="octicon octicon-file-media"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Image',
|
||||
props: ['src', 'alt'],
|
||||
data() {
|
||||
return {
|
||||
is_loading: true,
|
||||
is_broken: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.handle_image();
|
||||
},
|
||||
methods: {
|
||||
handle_image() {
|
||||
let img = new Image();
|
||||
img.src = this.src;
|
||||
|
||||
img.onload = () => {
|
||||
this.is_loading = false;
|
||||
};
|
||||
img.onerror = () => {
|
||||
this.is_loading = false;
|
||||
this.is_broken = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,142 +0,0 @@
|
||||
<template>
|
||||
<div v-if="seen" class="col-md-3 col-sm-4 col-xs-6 hub-card-container">
|
||||
<div class="hub-card"
|
||||
@click="on_click(item_id)"
|
||||
>
|
||||
<div class="hub-card-header flex justify-between">
|
||||
<div class="ellipsis" :style="{ width: '85%' }">
|
||||
<div class="hub-card-title ellipsis bold">{{ title }}</div>
|
||||
<div class="hub-card-subtitle ellipsis text-muted" v-html='subtitle'></div>
|
||||
</div>
|
||||
<i v-if="allow_clear"
|
||||
class="octicon octicon-x text-extra-muted"
|
||||
@click.stop="$emit('remove-item', item_id)"
|
||||
>
|
||||
</i>
|
||||
</div>
|
||||
<div class="hub-card-body">
|
||||
<base-image class="hub-card-image" :src="item.image" :alt="title" />
|
||||
<div class="hub-card-overlay">
|
||||
<div v-if="is_local" class="hub-card-overlay-body">
|
||||
<div class="hub-card-overlay-button">
|
||||
<button class="btn btn-default zoom-view">
|
||||
<i class="octicon octicon-pencil text-muted"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'item-card',
|
||||
props: ['item', 'item_id_fieldname', 'is_local', 'on_click', 'allow_clear', 'seen'],
|
||||
computed: {
|
||||
title() {
|
||||
const item_name = this.item.item_name || this.item.name;
|
||||
return strip_html(item_name);
|
||||
},
|
||||
subtitle() {
|
||||
const dot_spacer = '<span aria-hidden="true"> · </span>';
|
||||
if(this.is_local){
|
||||
return comment_when(this.item.creation);
|
||||
} else {
|
||||
let subtitle_items = [comment_when(this.item.creation)];
|
||||
const rating = this.item.average_rating;
|
||||
|
||||
if (rating > 0) {
|
||||
subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
|
||||
}
|
||||
|
||||
subtitle_items.push(this.item.company);
|
||||
|
||||
return subtitle_items.join(dot_spacer);
|
||||
}
|
||||
},
|
||||
item_id() {
|
||||
return this.item[this.item_id_fieldname];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "../../../../../../frappe/frappe/public/less/variables.less";
|
||||
|
||||
.hub-card {
|
||||
margin-bottom: 25px;
|
||||
position: relative;
|
||||
border: 1px solid @border-color;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover .hub-card-overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.octicon-x {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-card.closable {
|
||||
.octicon-x {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-card.is-local {
|
||||
&.active {
|
||||
.hub-card-header {
|
||||
background-color: #f4ffe5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hub-card-header {
|
||||
position: relative;
|
||||
padding: 12px 15px;
|
||||
height: 60px;
|
||||
border-bottom: 1px solid @border-color;
|
||||
}
|
||||
|
||||
.hub-card-body {
|
||||
position: relative;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.hub-card-overlay {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.hub-card-overlay-body {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hub-card-overlay-button {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.hub-card-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<div class="item-cards-container">
|
||||
<empty-state
|
||||
v-if="items.length === 0"
|
||||
:message="empty_state_message"
|
||||
:action="empty_state_action"
|
||||
:bordered="true"
|
||||
:height="empty_state_height"
|
||||
/>
|
||||
<item-card
|
||||
v-for="item in items"
|
||||
:key="container_name + '_' +item[item_id_fieldname]"
|
||||
:item="item"
|
||||
:item_id_fieldname="item_id_fieldname"
|
||||
:is_local="is_local"
|
||||
:on_click="on_click"
|
||||
:allow_clear="editable"
|
||||
:seen="item.hasOwnProperty('seen') ? item.seen : true"
|
||||
@remove-item="$emit('remove-item', item[item_id_fieldname])"
|
||||
>
|
||||
</item-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemCard from './ItemCard.vue';
|
||||
import EmptyState from './EmptyState.vue';
|
||||
|
||||
export default {
|
||||
name: 'item-cards-container',
|
||||
props: {
|
||||
container_name: String,
|
||||
items: Array,
|
||||
item_id_fieldname: String,
|
||||
is_local: Boolean,
|
||||
on_click: Function,
|
||||
editable: Boolean,
|
||||
|
||||
empty_state_message: String,
|
||||
empty_state_action: Object,
|
||||
empty_state_height: Number,
|
||||
empty_state_bordered: Boolean
|
||||
},
|
||||
components: {
|
||||
ItemCard,
|
||||
EmptyState
|
||||
},
|
||||
watch: {
|
||||
items() {
|
||||
// TODO: handling doesn't work
|
||||
frappe.dom.handle_broken_images($(this.$el));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.item-cards-container {
|
||||
margin: 0 -15px;
|
||||
overflow: overlay;
|
||||
}
|
||||
</style>
|
@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-list-item" :data-route="item.route">
|
||||
<div class="hub-list-left">
|
||||
<base-image class="hub-list-image" :src="item.image" />
|
||||
<div class="hub-list-body ellipsis">
|
||||
<div class="hub-list-title">{{item.item_name}}</div>
|
||||
<div class="hub-list-subtitle ellipsis">
|
||||
<slot name="subtitle"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hub-list-right" v-if="message">
|
||||
<span class="text-muted" v-html="frappe.datetime.comment_when(message.creation, true)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['item', 'message']
|
||||
}
|
||||
</script>
|
@ -1,38 +0,0 @@
|
||||
<template>
|
||||
<div v-if="message" class="subpage-message">
|
||||
<p class="text-muted flex">
|
||||
<span v-html="message"></span>
|
||||
<i class="octicon octicon-x text-extra-muted"
|
||||
@click="$emit('remove-message')"
|
||||
>
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'notification-message',
|
||||
props: {
|
||||
message: String,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.subpage-message {
|
||||
p {
|
||||
padding: 10px 15px;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 15px;
|
||||
background-color: #f9fbf7;
|
||||
border-radius: 4px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.octicon-x {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<span>
|
||||
<i v-for="index in max_rating"
|
||||
:key="index"
|
||||
class="fa fa-fw star-icon"
|
||||
:class="{'fa-star': index <= rating, 'fa-star-o': index > rating}"
|
||||
>
|
||||
</i>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['rating', 'max_rating']
|
||||
}
|
||||
</script>
|
@ -1,140 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="timeline-head">
|
||||
<div class="comment-input-wrapper">
|
||||
<div class="comment-input-header">
|
||||
<span class="text-muted">{{ __('Add your review') }}</span>
|
||||
<div class="btn btn-default btn-xs pull-right"
|
||||
@click="on_submit_review"
|
||||
:disabled="!(user_review.rating && user_review.subject)"
|
||||
>
|
||||
{{ __('Submit Review') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-input-container">
|
||||
<div class="rating-area text-muted">
|
||||
<span>{{ __('Your rating:') }}</span>
|
||||
<div
|
||||
v-for="i in [1, 2, 3, 4, 5]"
|
||||
:key="i"
|
||||
:class="['fa fa-fw', user_review.rating < i ? 'fa-star-o' : 'fa-star']"
|
||||
:data-index="i"
|
||||
@click="set_rating(i)"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-input-body margin-top" v-show="user_review.rating">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Subject"
|
||||
class="form-control margin-bottom"
|
||||
style="border-color: #ebeff2"
|
||||
v-model="user_review.subject"
|
||||
>
|
||||
<div ref="review-content"></div>
|
||||
<div>
|
||||
<span class="text-muted text-small">{{ __('Ctrl+Enter to submit') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-items">
|
||||
<review-timeline-item v-for="review in reviews"
|
||||
:key="review.user"
|
||||
:username="review.username"
|
||||
:avatar="review.user_image"
|
||||
:comment_when="when(review.modified)"
|
||||
:rating="review.rating"
|
||||
:subject="review.subject"
|
||||
:content="review.content"
|
||||
>
|
||||
</review-timeline-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ReviewTimelineItem from '../components/ReviewTimelineItem.vue';
|
||||
|
||||
export default {
|
||||
props: ['hub_item_name'],
|
||||
data() {
|
||||
return {
|
||||
user_review: {
|
||||
rating: 0,
|
||||
subject: '',
|
||||
content: ''
|
||||
},
|
||||
reviews: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ReviewTimelineItem
|
||||
},
|
||||
created() {
|
||||
this.get_item_reviews();
|
||||
},
|
||||
mounted() {
|
||||
this.make_input();
|
||||
},
|
||||
methods: {
|
||||
set_rating(i) {
|
||||
this.user_review.rating = i;
|
||||
},
|
||||
|
||||
when(datetime) {
|
||||
return comment_when(datetime);
|
||||
},
|
||||
|
||||
get_item_reviews() {
|
||||
hub.call('get_item_reviews', { hub_item_name: this.hub_item_name })
|
||||
.then(reviews => {
|
||||
this.reviews = reviews;
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
make_input() {
|
||||
this.review_content = frappe.ui.form.make_control({
|
||||
parent: this.$refs['review-content'],
|
||||
on_submit: this.on_submit_review.bind(this),
|
||||
no_wrapper: true,
|
||||
only_input: true,
|
||||
render_input: true,
|
||||
df: {
|
||||
fieldtype: 'Comment',
|
||||
fieldname: 'comment'
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
on_submit_review() {
|
||||
const review = Object.assign({}, this.user_review, {
|
||||
content: this.review_content.get_value()
|
||||
});
|
||||
|
||||
if (!hub.is_seller_registered()) {
|
||||
frappe.throw(__('You need to login as a Marketplace User before you can add any reviews.'));
|
||||
}
|
||||
|
||||
hub.call('add_item_review', {
|
||||
hub_item_name: this.hub_item_name,
|
||||
review: JSON.stringify(review)
|
||||
})
|
||||
.then(this.push_review.bind(this));
|
||||
|
||||
this.reset_user_review();
|
||||
},
|
||||
|
||||
reset_user_review() {
|
||||
this.user_review.rating = 0;
|
||||
this.user_review.subject = '';
|
||||
this.review_content.set_value('');
|
||||
},
|
||||
|
||||
push_review(review){
|
||||
this.reviews.unshift(review);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div class="media timeline-item user-content" data-doctype="${''}" data-name="${''}">
|
||||
<span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px">
|
||||
<!-- ${image_html} -->
|
||||
</span>
|
||||
<div class="pull-left media-body">
|
||||
<div class="media-content-wrapper">
|
||||
<div class="action-btns">
|
||||
<!-- ${edit_html} -->
|
||||
</div>
|
||||
|
||||
<div class="comment-header clearfix">
|
||||
<span class="pull-left avatar avatar-small visible-xs">
|
||||
<!-- ${image_html} -->
|
||||
</span>
|
||||
|
||||
<div class="asset-details">
|
||||
<span class="author-wrap">
|
||||
<i class="octicon octicon-quote hidden-xs fa-fw"></i>
|
||||
<span>
|
||||
{{ username }}
|
||||
</span>
|
||||
</span>
|
||||
<a class="text-muted">
|
||||
<span class="text-muted hidden-xs">–</span>
|
||||
<span class="hidden-xs" v-html="comment_when"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reply timeline-content-show">
|
||||
<div class="timeline-item-content">
|
||||
<p class="text-muted">
|
||||
<rating :rating="rating" :max_rating="5"></rating>
|
||||
</p>
|
||||
<h6 class="bold">{{ subject }}</h6>
|
||||
<p class="text-muted" v-html="content"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Rating from '../components/Rating.vue';
|
||||
|
||||
export default {
|
||||
props: ['username', 'comment_when', 'avatar', 'rating', 'subject', 'content'],
|
||||
components: {
|
||||
Rating
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-search-container">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@keydown.enter="on_input">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
placeholder: String,
|
||||
value: String,
|
||||
on_search: Function
|
||||
},
|
||||
methods: {
|
||||
on_input(event) {
|
||||
this.$emit('input', event.target.value);
|
||||
this.on_search();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<div class="hub-items-header level"><slot></slot></div>
|
||||
</template>
|
@ -1,9 +0,0 @@
|
||||
/* Saving this for later */
|
||||
<template>
|
||||
<div class="media timeline-item notification-content">
|
||||
<div class="small">
|
||||
<i class="octicon octicon-bookmark fa-fw"></i>
|
||||
<span title="Administrator"><b>4 weeks ago</b> Published 1 item to Marketplace</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -1,41 +0,0 @@
|
||||
function edit_details_dialog(params) {
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: __('Update Details'),
|
||||
fields: [
|
||||
{
|
||||
label: 'Item Name',
|
||||
fieldname: 'item_name',
|
||||
fieldtype: 'Data',
|
||||
default: params.defaults.item_name,
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: 'Hub Category',
|
||||
fieldname: 'hub_category',
|
||||
fieldtype: 'Autocomplete',
|
||||
default: params.defaults.hub_category,
|
||||
options: [],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: 'Description',
|
||||
fieldname: 'description',
|
||||
fieldtype: 'Text',
|
||||
default: params.defaults.description,
|
||||
options: [],
|
||||
reqd: 1
|
||||
}
|
||||
],
|
||||
primary_action_label: params.primary_action.label || __('Update Details'),
|
||||
primary_action: params.primary_action.fn
|
||||
});
|
||||
|
||||
hub.call('get_categories').then(categories => {
|
||||
categories = categories.map(d => d.name);
|
||||
dialog.fields_dict.hub_category.set_data(categories);
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
export { edit_details_dialog };
|
@ -1,39 +0,0 @@
|
||||
function ItemPublishDialog(primary_action, secondary_action) {
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: __('Edit Publishing Details'),
|
||||
fields: [
|
||||
{
|
||||
label: __('Item Code'),
|
||||
fieldname: 'item_code',
|
||||
fieldtype: 'Data',
|
||||
read_only: 1
|
||||
},
|
||||
{
|
||||
label: __('Hub Category'),
|
||||
fieldname: 'hub_category',
|
||||
fieldtype: 'Autocomplete',
|
||||
options: [],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __('Images'),
|
||||
fieldname: 'image_list',
|
||||
fieldtype: 'MultiSelect',
|
||||
options: [],
|
||||
reqd: 1
|
||||
}
|
||||
],
|
||||
primary_action_label: primary_action.label || __('Set Details'),
|
||||
primary_action: primary_action.fn,
|
||||
secondary_action: secondary_action.fn
|
||||
});
|
||||
|
||||
hub.call('get_categories').then(categories => {
|
||||
categories = categories.map(d => d.name);
|
||||
dialog.fields_dict.hub_category.set_data(categories);
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
export { ItemPublishDialog };
|
@ -1,56 +0,0 @@
|
||||
const ProfileDialog = (title = __('Edit Profile'), action={}) => {
|
||||
const fields = [
|
||||
{
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'company',
|
||||
label: __('Company'),
|
||||
options: 'Company'
|
||||
},
|
||||
{
|
||||
fieldtype: 'Read Only',
|
||||
fieldname: 'email',
|
||||
label: __('Email')
|
||||
},
|
||||
{
|
||||
label: __('About your company'),
|
||||
fieldname: 'company_description',
|
||||
fieldtype: 'Text'
|
||||
}
|
||||
];
|
||||
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: title,
|
||||
fields: fields,
|
||||
primary_action_label: action.label || __('Update'),
|
||||
primary_action: () => {
|
||||
const form_values = dialog.get_values();
|
||||
let values_filled = true;
|
||||
|
||||
// TODO: Say "we notice that the company description and logo isn't set. Please set them in master."
|
||||
// Only then allow to register
|
||||
|
||||
const mandatory_fields = ['company', 'company_description'];
|
||||
mandatory_fields.forEach(field => {
|
||||
const value = form_values[field];
|
||||
if (!value) {
|
||||
dialog.set_df_property(field, 'reqd', 1);
|
||||
values_filled = false;
|
||||
}
|
||||
});
|
||||
if (!values_filled) return;
|
||||
|
||||
action.on_submit(form_values);
|
||||
}
|
||||
});
|
||||
|
||||
// Post create
|
||||
const default_company = frappe.defaults.get_default('company');
|
||||
dialog.set_value('company', default_company);
|
||||
dialog.set_value('email', frappe.session.user);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
export {
|
||||
ProfileDialog
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
function get_review_html(review) {
|
||||
let username = review.username || review.user || __("Anonymous");
|
||||
|
||||
let image_html = review.user_image
|
||||
? `<div class="avatar-frame" style="background-image: url(${review.user_image})"></div>`
|
||||
: `<div class="standard-image" style="background-color: #fafbfc">${frappe.get_abbr(username)}</div>`
|
||||
|
||||
let edit_html = review.own
|
||||
? `<div class="pull-right hidden-xs close-btn-container">
|
||||
<span class="small text-muted">
|
||||
${'data.delete'}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pull-right edit-btn-container">
|
||||
<span class="small text-muted">
|
||||
${'data.edit'}
|
||||
</span>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
let rating_html = get_rating_html(review.rating);
|
||||
|
||||
return get_timeline_item(review, image_html, edit_html, rating_html);
|
||||
}
|
||||
|
||||
function get_timeline_item(data, image_html, edit_html, rating_html) {
|
||||
return `<div class="media timeline-item user-content" data-doctype="${''}" data-name="${''}">
|
||||
<span class="pull-left avatar avatar-medium hidden-xs" style="margin-top: 1px">
|
||||
${image_html}
|
||||
</span>
|
||||
<div class="pull-left media-body">
|
||||
<div class="media-content-wrapper">
|
||||
<div class="action-btns">${edit_html}</div>
|
||||
|
||||
<div class="comment-header clearfix">
|
||||
<span class="pull-left avatar avatar-small visible-xs">
|
||||
${image_html}
|
||||
</span>
|
||||
|
||||
<div class="asset-details">
|
||||
<span class="author-wrap">
|
||||
<i class="octicon octicon-quote hidden-xs fa-fw"></i>
|
||||
<span>${data.username}</span>
|
||||
</span>
|
||||
<a class="text-muted">
|
||||
<span class="text-muted hidden-xs">–</span>
|
||||
<span class="hidden-xs">${comment_when(data.modified)}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="reply timeline-content-show">
|
||||
<div class="timeline-item-content">
|
||||
<p class="text-muted">
|
||||
${rating_html}
|
||||
</p>
|
||||
<h6 class="bold">${data.subject}</h6>
|
||||
<p class="text-muted">
|
||||
${data.content}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function get_rating_html(rating) {
|
||||
let rating_html = ``;
|
||||
for (var i = 0; i < 5; i++) {
|
||||
let star_class = 'fa-star';
|
||||
if (i >= rating) star_class = 'fa-star-o';
|
||||
rating_html += `<i class='fa fa-fw ${star_class} star-icon' data-index=${i}></i>`;
|
||||
}
|
||||
return rating_html;
|
||||
}
|
||||
|
||||
export {
|
||||
get_review_html,
|
||||
get_rating_html
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user