mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-02 16:13:22 +00:00
refactor!: drop ecommerce in favor of webshop (#33265)
* refactor!: remove ecommerce item group field check Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove `e_commerce` directory Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove `get_context` from `item_group` https://frappeframework.com/docs/v14/user/en/guides/portal-development/context Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove related `./templates` Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(navbar): remove wishlist (ecommerce) Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(js): remove js from scripts Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove `www/all-products` Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove pages and js Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove js/customer_reviews Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(portal utils): remove shopping cart debtor account Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove e_commerce events from hooks Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(web): remove e_commerce js from bundle Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(setup): remove shopping cart setup Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove pages Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor(item): remove website item button Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(payment request): remove `on_payment_authorized` Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: @staticmethod `get_gateway_details` to avoid monkey patching, in custom apps https://discuss.erpnext.com/t/how-to-override-method-in-frappe/28786/36 Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(pages): remove product page Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(homepage): do not setup website items Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor(workspace): remove link to ecommerce settings Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(www): remove shop-by-category Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(homepage): remove featured product Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor: remove products in homepage Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor(homepage): remove explore button Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor: remove products fields from homepage Signed-off-by: Sabu Siyad <hello@ssiyad.com> * Revert "refactor!: @staticmethod `get_gateway_details`" This reverts commit 561bcd96680a930bb92627869502d9346b10611b. Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: remove payment gateway e_commerce import Signed-off-by: Sabu Siyad <hello@ssiyad.com> * chore: pre-commit Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!: pass `party` into `get_price` Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor: move `get_item_codes_by_attributes` to `utilities/product` Signed-off-by: Sabu Siyad <hello@ssiyad.com> * refactor!(quotation): input customer group Signed-off-by: Sabu Siyad <hello@ssiyad.com> * chore: pre-commit * refactor: remove custom `navbar_items.html` * refactor!(item): remove `published_in_website` * refactor: move `validate_duplicate_website_item` before rename * test: remove `test_shopping_cart_without_website_item` * chore: add doctype drop patch * refactor: removed website item related code * refactor: removed shopping_cart code * refactor: removed e-commerce related patches * refactor: removed website related fields from item group * fix: patch create_asset_depreciation_schedules_from_assets, KeyError: '0K BU64 AUY' --------- Signed-off-by: Sabu Siyad <hello@ssiyad.com> Co-authored-by: Rohit Waghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
<div class="card address-card h-100">
|
||||
<div class="btn btn-sm btn-default btn-change-address font-md" style="position: absolute; right: 0; top: 0;">
|
||||
{{ _('Change') }}
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="card-title">{{ address.title }}</div>
|
||||
<div class="card-text mb-2">
|
||||
{{ address.display }}
|
||||
</div>
|
||||
<a href="/addresses?name={{address.name}}" class="card-link">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-edit"></use>
|
||||
</svg>
|
||||
{{ _('Edit') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<div class="card address-card h-100">
|
||||
<div class="check" style="position: absolute; right: 15px; top: 15px;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ address.title }}</h5>
|
||||
<p class="card-text text-muted">
|
||||
{{ address.display }}
|
||||
</p>
|
||||
<a href="/addresses?name={{address.name}}" class="card-link">{{ _('Edit') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,189 +0,0 @@
|
||||
{% from "erpnext/templates/includes/cart/cart_macros.html" import show_address %}
|
||||
|
||||
{% if addresses | length == 1%}
|
||||
{% set select_address = True %}
|
||||
{% endif %}
|
||||
|
||||
<div class="mb-3 frappe-card p-5" data-section="shipping-address">
|
||||
<div class="d-flex">
|
||||
<div class="col-6 address-header"><h6>{{ _("Shipping Address") }}</h6></div>
|
||||
<div class="col-6" style="padding: 0;">
|
||||
<a class="ml-4 btn-new-address" role="button">{{ _("Add a new address") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
{% for address in shipping_addresses %}
|
||||
{% if doc.shipping_address_name == address.name %}
|
||||
<div class="row no-gutters" data-fieldname="shipping_address_name">
|
||||
<div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="shipping" data-active>
|
||||
{% include "templates/includes/cart/address_card.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Billing Address -->
|
||||
<div class="checkbox ml-1 mb-2">
|
||||
<label for="input_same_billing">
|
||||
<input type="checkbox" class="product-filter" id="input_same_billing" checked style="width: 14px !important">
|
||||
<span class="label-area font-md">{{ _('Billing Address is same as Shipping Address') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{% if billing_addresses %}
|
||||
<div class="mb-3 frappe-card p-5" data-section="billing-address">
|
||||
<div class="d-flex">
|
||||
<div class="col-6 address-header"><h6>{{ _("Billing Address") }}</h6></div>
|
||||
<div class="col-6" style="padding: 0;">
|
||||
<a class="ml-4 btn-new-address" role="button">{{ _("Add a new address") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
{% for address in billing_addresses %}
|
||||
{% if doc.customer_address == address.name %}
|
||||
<div class="row no-gutters" data-fieldname="customer_address">
|
||||
<div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="billing" data-active>
|
||||
{% include "templates/includes/cart/address_card.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
frappe.boot = {{ boot }}
|
||||
frappe.ready(() => {
|
||||
$(document).on('click', '.address-card', (e) => {
|
||||
const $target = $(e.currentTarget);
|
||||
const $section = $target.closest('[data-section]');
|
||||
$section.find('.address-card').removeClass('active');
|
||||
$target.addClass('active');
|
||||
});
|
||||
|
||||
$('#input_same_billing').change((e) => {
|
||||
const $check = $(e.target);
|
||||
toggle_billing_address_section(!$check.is(':checked'));
|
||||
});
|
||||
|
||||
$('.btn-new-address').click(() => {
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __('New Address'),
|
||||
fields: [
|
||||
{
|
||||
label: __('Address Title'),
|
||||
fieldname: 'address_title',
|
||||
fieldtype: 'Data',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __('Address Line 1'),
|
||||
fieldname: 'address_line1',
|
||||
fieldtype: 'Data',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __('Address Line 2'),
|
||||
fieldname: 'address_line2',
|
||||
fieldtype: 'Data'
|
||||
},
|
||||
{
|
||||
label: __('City/Town'),
|
||||
fieldname: 'city',
|
||||
fieldtype: 'Data',
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __('State'),
|
||||
fieldname: 'state',
|
||||
fieldtype: 'Data'
|
||||
},
|
||||
{
|
||||
label: __('Country'),
|
||||
fieldname: 'country',
|
||||
fieldtype: 'Link',
|
||||
options: 'Country',
|
||||
only_select: true,
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "column_break0",
|
||||
fieldtype: "Column Break",
|
||||
width: "50%"
|
||||
},
|
||||
{
|
||||
label: __('Address Type'),
|
||||
fieldname: 'address_type',
|
||||
fieldtype: 'Select',
|
||||
options: [
|
||||
'Billing',
|
||||
'Shipping'
|
||||
],
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
label: __('Postal Code'),
|
||||
fieldname: 'pincode',
|
||||
fieldtype: 'Data'
|
||||
},
|
||||
{
|
||||
fieldname: "phone",
|
||||
fieldtype: "Data",
|
||||
label: "Phone",
|
||||
reqd: 1
|
||||
},
|
||||
],
|
||||
primary_action_label: __('Save'),
|
||||
primary_action: (values) => {
|
||||
frappe.call('erpnext.e_commerce.shopping_cart.cart.add_new_address', { doc: values })
|
||||
.then(r => {
|
||||
frappe.call({
|
||||
method: "erpnext.e_commerce.shopping_cart.cart.update_cart_address",
|
||||
args: {
|
||||
address_type: r.message.address_type,
|
||||
address_name: r.message.name
|
||||
},
|
||||
callback: function (r) {
|
||||
d.hide();
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
d.show();
|
||||
});
|
||||
|
||||
function setup_state() {
|
||||
const shipping_address = $('[data-section="shipping-address"]')
|
||||
.find('[data-address-name][data-active]').attr('data-address-name');
|
||||
|
||||
const billing_address = $('[data-section="billing-address"]')
|
||||
.find('[data-address-name][data-active]').attr('data-address-name');
|
||||
|
||||
$('#input_same_billing').prop('checked', shipping_address === billing_address).trigger('change');
|
||||
|
||||
if (!shipping_address && !billing_address) {
|
||||
$('#input_same_billing').prop('checked', true).trigger('change');
|
||||
}
|
||||
|
||||
if (shipping_address) {
|
||||
$(`[data-section="shipping-address"] [data-address-name="${shipping_address}"] .address-card`).addClass('active');
|
||||
}
|
||||
if (billing_address) {
|
||||
$(`[data-section="billing-address"] [data-address-name="${billing_address}"] .address-card`).addClass('active');
|
||||
}
|
||||
}
|
||||
|
||||
setup_state();
|
||||
|
||||
function toggle_billing_address_section(flag) {
|
||||
$('[data-section="billing-address"]').toggle(flag);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,3 +0,0 @@
|
||||
<div class="mb-3 frappe-card p-5" data-section="shipping-address">
|
||||
<h6>{{ _("Shipping Address") }}</h6>
|
||||
</div>
|
||||
@@ -1,27 +0,0 @@
|
||||
<div class="cart-dropdown-container">
|
||||
<div id="cart-error" class="alert alert-danger"
|
||||
style="display: none;"></div>
|
||||
<div class="row checkout-btn">
|
||||
<div class="col-sm-12 col-xs-12">
|
||||
<a href="/cart" class="btn btn-block btn-primary">{{ _("Checkout") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row cart-items-dropdown cart-item-header text-muted">
|
||||
<div class="col-sm-6 col-xs-6 h6 text-uppercase">
|
||||
{{ _("Item") }}
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-6 text-right h6 text-uppercase">
|
||||
{{ _("Price") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if doc.items %}
|
||||
<div class="row cart-items-dropdown">
|
||||
<div class="col-sm-12 col-xs-12">
|
||||
{% include "templates/includes/cart/cart_items_dropdown.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p>{{ _("Cart is Empty") }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,113 +0,0 @@
|
||||
{% from "erpnext/templates/includes/macros.html" import product_image %}
|
||||
|
||||
{% macro item_subtotal(item) %}
|
||||
<div>
|
||||
{{ item.get_formatted('amount') }}
|
||||
</div>
|
||||
|
||||
{% if item.is_free_item %}
|
||||
<div class="text-success mt-4">
|
||||
<span class="free-tag">
|
||||
{{ _('FREE') }}
|
||||
</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="item-rate">
|
||||
{{ _('Rate:') }} {{ item.get_formatted('rate') }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% for d in doc.items %}
|
||||
<tr data-name="{{ d.name }}">
|
||||
<td style="width: 60%;">
|
||||
<div class="d-flex">
|
||||
<div class="cart-item-image mr-4">
|
||||
{% if d.thumbnail %}
|
||||
{{ product_image(d.thumbnail, alt="d.web_item_name", no_border=True) }}
|
||||
{% else %}
|
||||
<div class = "no-image-cart-item">
|
||||
{{ frappe.utils.get_abbr(d.web_item_name) or "NA" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="d-flex w-100" style="flex-direction: column;">
|
||||
<div class="item-title mb-1 mr-3">
|
||||
{{ d.get("web_item_name") or d.item_name }}
|
||||
</div>
|
||||
<div class="item-subtitle mr-2">
|
||||
{{ d.item_code }}
|
||||
</div>
|
||||
{%- set variant_of = frappe.db.get_value('Item', d.item_code, 'variant_of') %}
|
||||
{% if variant_of %}
|
||||
<span class="item-subtitle mr-2">
|
||||
{{ _('Variant of') }}
|
||||
<a href="{{frappe.db.get_value('Website Item', {'item_code': variant_of}, 'route') or '#'}}">
|
||||
{{ variant_of }}
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-2 notes">
|
||||
<textarea data-item-code="{{d.item_code}}" class="form-control" rows="2" placeholder="{{ _('Add notes') }}">
|
||||
{{d.additional_notes or ''}}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Qty column -->
|
||||
<td class="text-right" style="width: 25%;">
|
||||
<div class="d-flex">
|
||||
{% set disabled = 'disabled' if d.is_free_item else '' %}
|
||||
<div class="input-group number-spinner mt-1 mb-4">
|
||||
<span class="input-group-prepend d-sm-inline-block">
|
||||
<button class="btn cart-btn" data-dir="dwn" {{ disabled }}>
|
||||
{{ '–' if not d.is_free_item else ''}}
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<input class="form-control text-center cart-qty" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}"
|
||||
style="max-width: 70px;" {{ disabled }}>
|
||||
|
||||
<span class="input-group-append d-sm-inline-block">
|
||||
<button class="btn cart-btn" data-dir="up" {{ disabled }}>
|
||||
{{ '+' if not d.is_free_item else ''}}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if not d.is_free_item %}
|
||||
<div class="remove-cart-item column-sm-view d-flex" data-item-code="{{ d.item_code }}">
|
||||
<span>
|
||||
<svg class="icon sm remove-cart-item-logo"
|
||||
width="18" height="18" viewBox="0 0 18 18"
|
||||
xmlns="http://www.w3.org/2000/svg" id="icon-close">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.146 11.217a.5.5 0 1 0 .708.708l3.182-3.182 3.181 3.182a.5.5 0 1 0 .708-.708l-3.182-3.18 3.182-3.182a.5.5 0 1 0-.708-.708l-3.18 3.181-3.183-3.182a.5.5 0 0 0-.708.708l3.182 3.182-3.182 3.181z" stroke-width="0"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Shown on mobile view, else hidden -->
|
||||
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
|
||||
<div class="text-right sm-item-subtotal">
|
||||
{{ item_subtotal(d) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<!-- Subtotal column -->
|
||||
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
|
||||
<td class="text-right item-subtotal column-sm-view w-100">
|
||||
{{ item_subtotal(d) }}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
@@ -1,12 +0,0 @@
|
||||
{% from "erpnext/templates/includes/order/order_macros.html" import item_name_and_description_cart %}
|
||||
|
||||
{% for d in doc.items %}
|
||||
<div class="row cart-dropdown">
|
||||
<div class="col-sm-8 col-xs-8 col-name-description">
|
||||
{{ item_name_and_description_cart(d) }}
|
||||
</div>
|
||||
<div class="col-sm-4 col-xs-4 text-right col-amount">
|
||||
{{ d.get_formatted("amount") }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -1,10 +0,0 @@
|
||||
<!-- Total at the end of the cart items -->
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-left item-grand-total" colspan="1">
|
||||
{{ _("Total") }}
|
||||
</th>
|
||||
<th class="text-left item-grand-total totals" colspan="3">
|
||||
{{ doc.get_formatted("total") }}
|
||||
</th>
|
||||
</tr>
|
||||
@@ -1,22 +0,0 @@
|
||||
{% macro show_address(address, doc, fieldname, select_address=False) %}
|
||||
{% set selected=address.name==doc.get(fieldname) %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-sm-10 address-title"
|
||||
data-address-name="{{ address.name }}">
|
||||
<strong>{{ address.name }}</strong></div>
|
||||
<div class="col-sm-2 text-right">
|
||||
<input type="checkbox"
|
||||
data-fieldname="{{ fieldname }}"
|
||||
data-address-name="{{ address.name}}"
|
||||
{{ "checked" if selected else "" }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-collapse"
|
||||
data-address-name="{{ address.name }}">
|
||||
<div class="panel-body text-muted small">{{ address.display }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -1,84 +0,0 @@
|
||||
<!-- Payment -->
|
||||
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
|
||||
<h6>
|
||||
{{ _("Payment Summary") }}
|
||||
</h6>
|
||||
{% endif %}
|
||||
|
||||
<div class="card h-100">
|
||||
<div class="card-body p-0">
|
||||
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
|
||||
<table class="table w-100">
|
||||
<tr>
|
||||
{% set total_items = frappe.utils.cstr(frappe.utils.flt(doc.total_qty, 0)) %}
|
||||
<td class="bill-label">{{ _("Net Total (") + total_items + _(" Items)") }}</td>
|
||||
<td class="bill-content net-total text-right">{{ doc.get_formatted("net_total") }}</td>
|
||||
</tr>
|
||||
|
||||
<!-- taxes -->
|
||||
{% for d in doc.taxes %}
|
||||
{% if d.base_tax_amount %}
|
||||
<tr>
|
||||
<td class="bill-label">
|
||||
{{ d.description }}
|
||||
</td>
|
||||
<td class="bill-content text-right">
|
||||
{{ d.get_formatted("base_tax_amount") }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<!-- TODO: Apply Coupon Dialog-->
|
||||
<!-- {% set show_coupon_code = cart_settings.show_apply_coupon_code_in_website and cart_settings.enable_checkout %}
|
||||
{% if show_coupon_code %}
|
||||
<button class="btn btn-coupon-code w-100 text-left">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" stroke="var(--gray-600)" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 15.6213C19 15.2235 19.158 14.842 19.4393 14.5607L20.9393 13.0607C21.5251 12.4749 21.5251 11.5251 20.9393 10.9393L19.4393 9.43934C19.158 9.15804 19 8.7765 19 8.37868V6.5C19 5.67157 18.3284 5 17.5 5H15.6213C15.2235 5 14.842 4.84196 14.5607 4.56066L13.0607 3.06066C12.4749 2.47487 11.5251 2.47487 10.9393 3.06066L9.43934 4.56066C9.15804 4.84196 8.7765 5 8.37868 5H6.5C5.67157 5 5 5.67157 5 6.5V8.37868C5 8.7765 4.84196 9.15804 4.56066 9.43934L3.06066 10.9393C2.47487 11.5251 2.47487 12.4749 3.06066 13.0607L4.56066 14.5607C4.84196 14.842 5 15.2235 5 15.6213V17.5C5 18.3284 5.67157 19 6.5 19H8.37868C8.7765 19 9.15804 19.158 9.43934 19.4393L10.9393 20.9393C11.5251 21.5251 12.4749 21.5251 13.0607 20.9393L14.5607 19.4393C14.842 19.158 15.2235 19 15.6213 19H17.5C18.3284 19 19 18.3284 19 17.5V15.6213Z" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15 9L9 15" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.5 9.5C10.5 10.0523 10.0523 10.5 9.5 10.5C8.94772 10.5 8.5 10.0523 8.5 9.5C8.5 8.94772 8.94772 8.5 9.5 8.5C10.0523 8.5 10.5 8.94772 10.5 9.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.5 14.5C15.5 15.0523 15.0523 15.5 14.5 15.5C13.9477 15.5 13.5 15.0523 13.5 14.5C13.5 13.9477 13.9477 13.5 14.5 13.5C15.0523 13.5 15.5 13.9477 15.5 14.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<span class="ml-2">Apply Coupon</span>
|
||||
</button>
|
||||
{% endif %} -->
|
||||
|
||||
<table class="table w-100 grand-total mt-6">
|
||||
<tr>
|
||||
<td class="bill-content net-total">{{ _("Grand Total") }}</td>
|
||||
<td class="bill-content net-total text-right">{{ doc.get_formatted("grand_total") }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if cart_settings.enable_checkout %}
|
||||
<button class="btn btn-primary btn-place-order font-md w-100" type="button">
|
||||
{{ _('Place Order') }}
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary btn-request-for-quotation font-md w-100" type="button">
|
||||
{{ _('Request for Quote') }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TODO: Apply Coupon Dialog-->
|
||||
<!-- <script>
|
||||
frappe.ready(() => {
|
||||
$('.btn-coupon-code').click((e) => {
|
||||
const $btn = $(e.currentTarget);
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __('Coupons'),
|
||||
fields: [
|
||||
{
|
||||
fieldname: 'coupons_area',
|
||||
fieldtype: 'HTML'
|
||||
}
|
||||
]
|
||||
});
|
||||
d.show();
|
||||
});
|
||||
});
|
||||
</script> -->
|
||||
@@ -1,22 +0,0 @@
|
||||
{% extends 'frappe/templates/includes/navbar/navbar_items.html' %}
|
||||
|
||||
{% block navbar_right_extension %}
|
||||
<li class="shopping-cart cart-icon hidden">
|
||||
<a class="nav-link" href="/cart">
|
||||
<svg class="icon icon-lg">
|
||||
<use href="#icon-assets"></use>
|
||||
</svg>
|
||||
<span class="badge badge-primary shopping-badge" id="cart-count"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% if frappe.db.get_single_value("E Commerce Settings", "enable_wishlist") %}
|
||||
<li class="wishlist wishlist-icon hidden">
|
||||
<a class="nav-link" href="/wishlist">
|
||||
<svg class="icon icon-lg">
|
||||
<use href="#icon-heart"></use>
|
||||
</svg>
|
||||
<span class="badge badge-primary shopping-badge" id="wish-count"></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,52 +0,0 @@
|
||||
{% from "erpnext/templates/includes/macros.html" import product_image %}
|
||||
|
||||
{% macro item_name_and_description(d) %}
|
||||
<div class="row item_name_and_description">
|
||||
<div class="col-xs-4 col-sm-2 order-image-col">
|
||||
<div class="order-image h-100">
|
||||
{% if d.thumbnail or d.image %}
|
||||
{{ product_image(d.thumbnail or d.image, no_border=True) }}
|
||||
{% else %}
|
||||
<div class="no-image-cart-item" style="min-height: 100px;">
|
||||
{{ frappe.utils.get_abbr(d.item_name) or "NA" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-10">
|
||||
{{ d.item_code }}
|
||||
<div class="text-muted small item-description">
|
||||
{{ html2text(d.description) | truncate(140) }}
|
||||
</div>
|
||||
<span class="text-muted mt-2 d-l-n order-qty">
|
||||
{{ _("Qty ") }}({{ d.get_formatted("qty") }})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro item_name_and_description_cart(d) %}
|
||||
<div class="row item_name_dropdown">
|
||||
<div class="col-xs-4 col-sm-4 order-image-col">
|
||||
<div class="order-image">
|
||||
{{ product_image_square(d.thumbnail or d.image) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-8 col-sm-8">
|
||||
{{ d.item_name|truncate(25) }}
|
||||
<div class="input-group number-spinner">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-light cart-btn" data-dir="dwn">
|
||||
–</button>
|
||||
</span>
|
||||
<input class="form-control text-right cart-qty"
|
||||
value = "{{ d.get_formatted('qty') }}"
|
||||
data-item-code="{{ d.item_code }}">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-light cart-btn" data-dir="up">
|
||||
+</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -1,217 +0,0 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.ready(function() {
|
||||
window.item_code = $('[itemscope] [itemprop="productID"]').text().trim();
|
||||
var qty = 0;
|
||||
|
||||
frappe.call({
|
||||
type: "POST",
|
||||
method: "erpnext.e_commerce.shopping_cart.product_info.get_product_info_for_website",
|
||||
args: {
|
||||
item_code: get_item_code()
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
if(r.message.cart_settings.enabled) {
|
||||
let hide_add_to_cart = !r.message.product_info.price
|
||||
|| (!r.message.product_info.in_stock && !r.message.cart_settings.allow_items_not_in_stock);
|
||||
$(".item-cart, .item-price, .item-stock").toggleClass('hide', hide_add_to_cart);
|
||||
}
|
||||
if(r.message.cart_settings.show_price) {
|
||||
$(".item-price").toggleClass("hide", false);
|
||||
}
|
||||
if(r.message.cart_settings.show_stock_availability) {
|
||||
$(".item-stock").toggleClass("hide", false);
|
||||
}
|
||||
if(r.message.product_info.price) {
|
||||
$(".item-price")
|
||||
.html(r.message.product_info.price.formatted_price_sales_uom + "<div style='font-size: small'>\
|
||||
(" + r.message.product_info.price.formatted_price + " / " + r.message.product_info.uom + ")</div>");
|
||||
|
||||
if(r.message.product_info.in_stock===0) {
|
||||
$(".item-stock").html("<div style='color: red'> <i class='fa fa-close'></i> {{ _("Not in stock") }}</div>");
|
||||
}
|
||||
else if(r.message.product_info.in_stock===1 && r.message.cart_settings.show_stock_availability) {
|
||||
var qty_display = "{{ _("In stock") }}";
|
||||
if (r.message.product_info.show_stock_qty) {
|
||||
qty_display += " ("+r.message.product_info.stock_qty+")";
|
||||
}
|
||||
$(".item-stock").html("<div style='color: green'>\
|
||||
<i class='fa fa-check'></i> "+qty_display+"</div>");
|
||||
}
|
||||
|
||||
if(r.message.product_info.qty) {
|
||||
qty = r.message.product_info.qty;
|
||||
toggle_update_cart(r.message.product_info.qty);
|
||||
} else {
|
||||
toggle_update_cart(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$("#item-add-to-cart button").on("click", function() {
|
||||
frappe.provide('erpnext.shopping_cart');
|
||||
|
||||
erpnext.shopping_cart.update_cart({
|
||||
item_code: get_item_code(),
|
||||
qty: $("#item-spinner .cart-qty").val(),
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
toggle_update_cart(1);
|
||||
qty = 1;
|
||||
}
|
||||
},
|
||||
btn: this,
|
||||
});
|
||||
});
|
||||
|
||||
$("#item-spinner").on('click', '.number-spinner button', function () {
|
||||
var btn = $(this),
|
||||
input = btn.closest('.number-spinner').find('input'),
|
||||
oldValue = input.val().trim(),
|
||||
newVal = 0;
|
||||
|
||||
if (btn.attr('data-dir') == 'up') {
|
||||
newVal = Number.parseInt(oldValue) + 1;
|
||||
} else if (btn.attr('data-dir') == 'dwn') {
|
||||
if (Number.parseInt(oldValue) > 1) {
|
||||
newVal = Number.parseInt(oldValue) - 1;
|
||||
}
|
||||
else {
|
||||
newVal = Number.parseInt(oldValue);
|
||||
}
|
||||
}
|
||||
input.val(newVal);
|
||||
});
|
||||
|
||||
$("[itemscope] .item-view-attribute .form-control").on("change", function() {
|
||||
try {
|
||||
var item_code = encodeURIComponent(get_item_code());
|
||||
|
||||
} catch(e) {
|
||||
// unable to find variant
|
||||
// then chose the closest available one
|
||||
|
||||
var attribute = $(this).attr("data-attribute");
|
||||
var attribute_value = $(this).val();
|
||||
var item_code = find_closest_match(attribute, attribute_value);
|
||||
|
||||
if (!item_code) {
|
||||
frappe.msgprint(__("Cannot find a matching Item. Please select some other value for {0}.", [attribute]))
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (window.location.search == ("?variant=" + item_code) || window.location.search.includes(item_code)) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = window.location.pathname + "?variant=" + item_code;
|
||||
});
|
||||
|
||||
// change the item image src when alternate images are hovered
|
||||
$(document.body).on('mouseover', '.item-alternative-image', (e) => {
|
||||
const $alternative_image = $(e.currentTarget);
|
||||
const src = $alternative_image.find('img').prop('src');
|
||||
$('.item-image img').prop('src', src);
|
||||
});
|
||||
});
|
||||
|
||||
var toggle_update_cart = function(qty) {
|
||||
$("#item-add-to-cart").toggle(qty ? false : true);
|
||||
$("#item-update-cart")
|
||||
.toggle(qty ? true : false)
|
||||
.find("input").val(qty);
|
||||
$("#item-spinner").toggle(qty ? false : true);
|
||||
}
|
||||
|
||||
function get_item_code() {
|
||||
var variant_info = window.variant_info;
|
||||
if(variant_info) {
|
||||
var attributes = get_selected_attributes();
|
||||
var no_of_attributes = Object.keys(attributes).length;
|
||||
|
||||
for(var i in variant_info) {
|
||||
var variant = variant_info[i];
|
||||
|
||||
if (variant.attributes.length < no_of_attributes) {
|
||||
// the case when variant has less attributes than template
|
||||
continue;
|
||||
}
|
||||
|
||||
var match = true;
|
||||
for(var j in variant.attributes) {
|
||||
if(attributes[variant.attributes[j].attribute]
|
||||
!= variant.attributes[j].attribute_value
|
||||
) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(match) {
|
||||
return variant.name;
|
||||
}
|
||||
}
|
||||
throw "Unable to match variant";
|
||||
} else {
|
||||
return window.item_code;
|
||||
}
|
||||
}
|
||||
|
||||
function find_closest_match(selected_attribute, selected_attribute_value) {
|
||||
// find the closest match keeping the selected attribute in focus and get the item code
|
||||
|
||||
var attributes = get_selected_attributes();
|
||||
|
||||
var previous_match_score = 0;
|
||||
var previous_no_of_attributes = 0;
|
||||
var matched;
|
||||
|
||||
var variant_info = window.variant_info;
|
||||
for(var i in variant_info) {
|
||||
var variant = variant_info[i];
|
||||
var match_score = 0;
|
||||
var has_selected_attribute = false;
|
||||
|
||||
for(var j in variant.attributes) {
|
||||
if(attributes[variant.attributes[j].attribute]===variant.attributes[j].attribute_value) {
|
||||
match_score = match_score + 1;
|
||||
|
||||
if (variant.attributes[j].attribute==selected_attribute && variant.attributes[j].attribute_value==selected_attribute_value) {
|
||||
has_selected_attribute = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_selected_attribute
|
||||
&& ((match_score > previous_match_score) || (match_score==previous_match_score && previous_no_of_attributes < variant.attributes.length))) {
|
||||
previous_match_score = match_score;
|
||||
matched = variant;
|
||||
previous_no_of_attributes = variant.attributes.length;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
for (var j in matched.attributes) {
|
||||
var attr = matched.attributes[j];
|
||||
$('[itemscope]')
|
||||
.find(repl('.item-view-attribute .form-control[data-attribute="%(attribute)s"]', attr))
|
||||
.val(attr.attribute_value);
|
||||
}
|
||||
|
||||
return matched.name;
|
||||
}
|
||||
}
|
||||
|
||||
function get_selected_attributes() {
|
||||
var attributes = {};
|
||||
$('[itemscope]').find(".item-view-attribute .form-control").each(function() {
|
||||
attributes[$(this).attr('data-attribute')] = $(this).val();
|
||||
});
|
||||
return attributes;
|
||||
}
|
||||
Reference in New Issue
Block a user