File manager - Edit - /var/www/payraty/inventory_main/resources/js/components/admin/invoices/InvoiceAdd.vue
Back
<template> <div class="row"> <!-- Modal --> <div v-if="isModalOpen" class="modal-overlay"> <div class="modal-content"> <!-- Modal Header --> <div class="modal-header"> <h2>Receipt #332</h2> <button @click="closeModal" class="close-button">×</button> </div> <div class="modal-body"> <p><strong>Amount Paid:</strong> {{ calculateTotalWithOutTax() }}</p> <p><strong>Total Discount:</strong> {{ currency_symbol }} {{ calculateTotalDiscount() }}</p> <hr /> <!-- Email Receipt Toggle --> <div class="toggle-option"> <span>Email Receipt</span> <label class="switch"> <input type="checkbox" v-model="emailReceiptEnabled" /> <span class="slider"></span> </label> </div> <!-- Print Receipt Toggle --> <div class="toggle-option"> <span>Print Receipt</span> <label class="switch"> <input type="checkbox" v-model="printReceiptEnabled" /> <span class="slider"></span> </label> </div> <!-- Number of Receipts Counter --> <div class="number-counter"> <span># of Receipt</span> <div class="counter-controls"> <button @click="decrementReceiptCount" class="counter-button">-</button> <input type="number" v-model="receiptCount" min="1" class="counter-input" /> <button @click="incrementReceiptCount" class="counter-button">+</button> </div> </div> </div> <!-- Modal Footer --> <div class="modal-footer-b"> <button @click="closeModal" class="cancel-button">Cancel</button> <button @click="printReceipt" class="print-button no-print">Print</button> </div> </div> </div> <!-- Printable Receipt Content --> <div class="printable-content" v-if="isPrinting"> <div class="receipt-header"> <h1>{{ organisationData.name }}</h1> <p>{{ organisationData.address }}</p> <p>{{ organisationData.phone }}</p> <p>{{ currentDate }}</p> </div> <div class="receipt-details"> <p><span>Order ID:</span> <span>REF5246378</span></p> <p><span>Transaction ID:</span> <span>65G4R6UHR</span></p> <p><span>Type:</span> <span>CREDIT</span></p> </div> <div class="receipt-summary"> <p><span>Total Discount:</span> <span>{{ currency_symbol }} {{ calculateTotalDiscount() }}</span></p> <p><span>Tax (10%):</span> <span>{{ currency_symbol }} {{ totalTax() }}</span></p> <p><span>Coupon:</span> <span>{{ formData.coupon.code }}</span></p> <p class="total-amount"><span>Total Amount:</span> <span>{{ currency_symbol }} {{ calculateTotalWithTax() }}</span></p> </div> <div class="receipt-items"> <h3>Your Order</h3> <table> <thead> <tr> <th>Item</th> <th>Quantity</th> <th>Price</th> </tr> </thead> <tbody> <tr v-for="(item, index) in formData.items" :key="index"> <td>{{ item.name }}</td> <td>{{ item.quantity }}</td> <td>₦{{ item.price.toLocaleString() }}</td> </tr> </tbody> </table> </div> <div class="receipt-payment"> <p><span>Number:</span> <span>XXXXXXXXXX8675</span></p> <p><span>Card Type:</span> <span>MasterCard</span></p> <p><span>Response:</span> <span>A</span></p> <p><span>Approval Code:</span> <span>575467</span></p> </div> <div class="receipt-footer"> <p>Thanks for supporting our business</p> <p>THANK YOU</p> </div> </div> <div class="col-12" v-if="isExistsValidationErrors"> <div class="row"> <div class="col-12"> <div class="alert alert-danger alert-important alert-dismissible fade show mb-0" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> <li v-for="(validationError, index) in validationErrors.errors" :key="index"> {{ validationError[0] }} </li> </div> </div> </div> </div> <div class="col-12"> <div class="row"> <div class="col-lg-5 col-xl-6"> <div class="card"> <div class="card-body"> <h4>Product Categories</h4> <button @click="openModal" class="btn btn-dark btn-block barcode-btn open-modal-button">View Receipt</button> <div class="row" style="margin:50px 0px"> <!-- Category Buttons --> <div class="col-sm-12 col-lg-12 col-md-12"> <div class="category-buttons"> <button v-for="category in categories" :key="category.id" @click="selectCategory(category)" :class="{ active: selected_category === category }"> <!-- Category Image --> <img :src="getImageUrl(category.image)" :alt="category.text" class="category-image" @error="handleImageError" /> <!-- Category Name --> <span class="category-name">{{ category.text }}</span> </button> </div> </div> </div> <h4>Top Products</h4> <div class="ic-product-head" v-if="showProduct"> <div v-for="(product_stock, index) in product_list" :key="index" class="product-items pt-0"> <div class="product-item" @click="addNewItem(product_stock)"> <div class="ic-images-out-of-stock"> <img class="img-fluid list-image card-img-top" :src="product_stock.product.thumb_url" alt="Product" /> <div v-if="product_stock.product.stock < 1" class="ic-stock-overlay"> <p>{{ __("custom.stock_out") }}</p> </div> </div> <div class="product-item-body p-2"> <label class="m-0">{{ product_stock.product.name }}</label> <p class="card-text p-0 m-0" v-if="product_stock.product.is_variant == 1"> {{ product_stock.attribute.name }}: {{ product_stock.attribute_item.name }} </p> <p class="card-text p-0 m-0"> {{ __("custom.price") }}: {{ currency_symbol }} {{ product_stock.price_for_sale }} </p> <p class="card-text p-0 m-0"> {{ __("custom.stock") }}: {{ product_stock.quantity }} </p> </div> </div> </div> </div> <div v-else> <p class="text-white m-0">{{ __("custom.no_product_found") }}</p> </div> </div> </div> </div> <div class="col-lg-7 col-xl-6"> <div class="card"> <div class="card-body"> <h4 class="order-list">Product</h4> </div> </div> <div class="card"> <div class="card-body"> <div class="form-group mb-0"> <div> <label class="float-left label-text"><span class="mr-1">Product Name</span> </label> <div class="product-main-box"> <form @submit.prevent="submitBarcode"> <div class="form-group"> <input v-focus v-model="search" type="text" class="form-control product-input" placeholder="Search Product or Barcode..." @keyup="searchSelectSku" /> </div> </form> </div> </div> </div> <div class="form-group mb-0"> <div> <label class="float-left label-text"><span class="mr-1">Customer Name</span> </label> <div class="custom-control custom-checkbox float-right"> <input v-model="formData.is_walkin_customer" class="form-check-input custom-control-input" type="checkbox" id="walkinCustomer" @click="btnWalkinCustomer" /> <label class="form-check-label custom-control-label checkbox-label walkin-text" for="walkinCustomer"> {{ __("custom.walk_in_customer") }} </label> </div> </div> <Select2 v-if="!formData.is_walkin_customer" v-model="formData.customer_id" :id="'customer-id'" :options="customers" :settings="{ placeholder: 'Select Customer' }" @select="selectedCustomer($event)"> </Select2> </div> <div class="w-100" v-if="formData.is_walkin_customer"> <div class="from-group customer-main-box"> <label for="" class="label-text"></label> <input type="text" class="form-control product-input" placeholder="Customer Name" v-model="formData.walkin_customer.full_name" /> </div> <div class="from-group"> <label for="" class="label-text">{{ __("custom.phone") }}</label> <input type="text" class="form-control product-input" placeholder="Phone" v-model="formData.walkin_customer.phone" /> </div> </div> <div class="scan-barcode"> <button type="button" class="btn btn-dark btn-block barcode-btn"> <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <path d="M4 6H6V18H4V6ZM7 6H8V18H7V6ZM9 6H12V18H9V6ZM13 6H14V18H13V6ZM16 6H18V18H16V6ZM19 6H20V18H19V6ZM2 4V8H0V4C0 3.46957 0.210714 2.96086 0.585786 2.58579C0.960859 2.21071 1.46957 2 2 2H6V4H2ZM22 2C22.5304 2 23.0391 2.21071 23.4142 2.58579C23.7893 2.96086 24 3.46957 24 4V8H22V4H18V2H22ZM2 16V20H6V22H2C1.46957 22 0.960859 21.7893 0.585786 21.4142C0.210714 21.0391 0 20.5304 0 20V16H2ZM22 20V16H24V20C24 20.5304 23.7893 21.0391 23.4142 21.4142C23.0391 21.7893 22.5304 22 22 22H18V20H22Z" fill="currentColor" /> </svg> <span>Scan Barcode</span> </button> </div> </div> </div> <div v-for="(item, index) in formData.items" :key="index" class="card"> <div class="card-body product-box"> <div class="product-item-box"> <div class="product-item-box-2"> <div class="product-item-img"> <img class="img-fluid list-image card-img-top" :src="item.thumb_url || '/images/default.png'" alt="product" /> </div> <div class="product-item-name"> <div> <p class="p-0 m-0 product-name" v-if="item.is_variant"> {{ truncateText(item.name + ' (' + item.attribute.name + ':' + item.attribute_item.name + ')', 40) }} </p> <p class="p-0 m-0 product-name" v-else> {{ truncateText(item.name, 40) }} </p> </div> <div class="quantity-box"> <span @click="decreaseQuantity(index)" class="quantity-icon"> <i class="fa fa-minus"></i> </span> <span class="quantity-input"> <input type="number" v-if="item.split_sale" min="1" step="any" v-model="item.quantity" @input="updateQuantity($event, index)" class="form-control text-center border quantity-input-field" /> <input type="number" v-else min="1" onkeydown="if(event.key==='.'){event.preventDefault();}" oninput="event.target.value = event.target.value.replace(/[^0-9]*/g,'');" v-model="item.quantity" @input="updateQuantity($event, index)" class="form-control text-center border quantity-input-field" /> </span> <span @click="increaseQuantity(index)" class="quantity-icon"> <i class="fa fa-plus"></i> </span> </div> </div> </div> <div class="product-item-price"> <div> <span class="product-sub-total"> {{ calculateSubtotal(index) }}</span> </div> <div class="remove-item-box"> <button type="button" class="btn btn-sm remove-item-button" @click.prevent="deleteItem(index)"> <i class="fa-regular fa-circle-xmark"></i> </button> </div> </div> </div> </div> </div> <div class="card"> <div class="card-body"> <div class="order-summary-box"> <div class="order-summary-list"> <div class="order-summary-title"> <span>Discount</span> </div> <div class="order-summary-value"> <span v-if="calculateTotalDiscount()"> {{ currency_symbol }} {{ calculateTotalDiscount() }} </span> <span v-else>N/A</span> </div> </div> <div class="order-summary-list"> <div class="order-summary-title"> <span>Service Charge</span> </div> <div class="order-summary-value"> <span>-</span> </div> </div> <div class="order-summary-list"> <div class="order-summary-title"> <span>Sub Total</span> </div> <div class="order-summary-value"> <span>{{ calculateTotalWithOutTax() }}</span> </div> </div> <div class="order-summary-list"> <div class="order-summary-title"> <span>Tax / VAT</span> </div> <div class="order-summary-value"> <span>{{ currency_symbol }} {{ totalTax() }}</span> </div> </div> <div class="order-summary-list"> <div class="order-summary-title"> <span>Coupon</span> </div> <div class="order-summary-value"> <span> <input class="form-control input-sm coupon-input" name="coupon" v-model="formData.coupon.code" /> </span> <span @click="applyCoupon" class="coupon-btn"> Apply </span> </div> </div> </div> <div class="order-total"> <div class="order-total-list"> <div class="order-total-title"> <span>Total Amount</span> </div> <div class="order-total-value"> <span>{{ calculateTotalWithTax() }}</span> </div> </div> </div> <div class="payment-box"> <div class="ic-payment-method"> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="bank" id="bank" name="payment_type" /> <label class="radio-inline radio-image payment-label" for="bank"> <svg width="21" height="22" viewBox="0 0 21 22" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <path d="M15 14.25H20.5V15.75H15V17.5L12.5 15L15 12.5V14.25ZM18 18.5V16.75L20.5 19.25L18 21.75V20H12.5V18.5H18ZM8 4.25C7.46957 4.25 6.96086 4.03929 6.58579 3.66421C6.21071 3.28914 6 2.78043 6 2.25C6 1.71957 6.21071 1.21086 6.58579 0.835786C6.96086 0.460714 7.46957 0.25 8 0.25C8.53043 0.25 9.03914 0.460714 9.41421 0.835786C9.78929 1.21086 10 1.71957 10 2.25C10 2.78043 9.78929 3.28914 9.41421 3.66421C9.03914 4.03929 8.53043 4.25 8 4.25ZM4.25 7.65L2.5 8.4V11.75H0.5V7.05L5.75 4.9C6 4.8 6.25 4.75 6.5 4.75C7.2 4.75 7.85 5.1 8.2 5.7L9.15 7.3C10.05 8.75 11.65 9.75 13.5 9.75V11.75C11.3 11.75 9.35 10.75 8.05 9.15L7.45 12.15L9.5 14.2V21.75H7.5V15.75L5.35 13.75L3.6 21.75H1.5L4.25 7.65Z" fill="currentColor" /> </svg> <p>Transfer</p> </label> </div> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="cash" id="cash" name="payment_type" /> <label class="radio-inline radio-image payment-label" for="cash"> <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <path d="M1.25 3.75C1.25 3.41848 1.3817 3.10054 1.61612 2.86612C1.85054 2.6317 2.16848 2.5 2.5 2.5H17.5C17.8315 2.5 18.1495 2.6317 18.3839 2.86612C18.6183 3.10054 18.75 3.41848 18.75 3.75H1.25ZM10 13.75C10.663 13.75 11.2989 13.4866 11.7678 13.0178C12.2366 12.5489 12.5 11.913 12.5 11.25C12.5 10.587 12.2366 9.95107 11.7678 9.48223C11.2989 9.01339 10.663 8.75 10 8.75C9.33696 8.75 8.70107 9.01339 8.23223 9.48223C7.76339 9.95107 7.5 10.587 7.5 11.25C7.5 11.913 7.76339 12.5489 8.23223 13.0178C8.70107 13.4866 9.33696 13.75 10 13.75Z" fill="#012060" /> <path d="M0 6.25C0 5.91848 0.131696 5.60054 0.366117 5.36612C0.600537 5.1317 0.918479 5 1.25 5H18.75C19.0815 5 19.3995 5.1317 19.6339 5.36612C19.8683 5.60054 20 5.91848 20 6.25V16.25C20 16.5815 19.8683 16.8995 19.6339 17.1339C19.3995 17.3683 19.0815 17.5 18.75 17.5H1.25C0.918479 17.5 0.600537 17.3683 0.366117 17.1339C0.131696 16.8995 0 16.5815 0 16.25V6.25ZM3.75 6.25C3.75 6.91304 3.48661 7.54893 3.01777 8.01777C2.54893 8.48661 1.91304 8.75 1.25 8.75V13.75C1.91304 13.75 2.54893 14.0134 3.01777 14.4822C3.48661 14.9511 3.75 15.587 3.75 16.25H16.25C16.25 15.587 16.5134 14.9511 16.9822 14.4822C17.4511 14.0134 18.087 13.75 18.75 13.75V8.75C18.087 8.75 17.4511 8.48661 16.9822 8.01777C16.5134 7.54893 16.25 6.91304 16.25 6.25H3.75Z" fill="currentColor" /> </svg> <p>Cash</p> </label> </div> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="online" id="online" name="payment_type" /> <label class="radio-inline radio-image payment-label" for="online"> <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_1414_28263)"> <path d="M3.1875 12.1875H5.6875V13.75H3.1875V12.1875Z" fill="#currentColor" /> <path d="M19.1501 3.125H0.850121C0.735777 3.12661 0.622895 3.15094 0.518041 3.19658C0.413187 3.24222 0.318456 3.30825 0.239358 3.39084C0.160261 3.47342 0.098376 3.57092 0.0573045 3.67764C0.016233 3.78437 -0.0032052 3.89819 0.000120756 4.0125V15.9875C-0.0032052 16.1018 0.016233 16.2156 0.0573045 16.3224C0.098376 16.4291 0.160261 16.5266 0.239358 16.6092C0.318456 16.6918 0.413187 16.7578 0.518041 16.8034C0.622895 16.8491 0.735777 16.8734 0.850121 16.875H19.1501C19.2645 16.8734 19.3773 16.8491 19.4822 16.8034C19.5871 16.7578 19.6818 16.6918 19.7609 16.6092C19.84 16.5266 19.9019 16.4291 19.9429 16.3224C19.984 16.2156 20.0034 16.1018 20.0001 15.9875V4.0125C20.0034 3.89819 19.984 3.78437 19.9429 3.67764C19.9019 3.57092 19.84 3.47342 19.7609 3.39084C19.6818 3.30825 19.5871 3.24222 19.4822 3.19658C19.3773 3.15094 19.2645 3.12661 19.1501 3.125ZM18.4376 4.6875V6.25H1.56262V4.6875H18.4376ZM1.56262 15.3125V9.375H18.4376V15.3125H1.56262Z" fill="currentColor" /> </g> <defs> <clipPath id="clip0_1414_28263"> <rect width="20" height="20" fill="currentColor" /> </clipPath> </defs> </svg> <p>Credit Card</p> </label> </div> </div> </div> <button v-if="!checkoutClicked" @click="handleCheckout" class="checkout-box" :disabled="!cartNotEmpty" :class="{ 'checkout-box-disabled': !cartNotEmpty }"> <div class="checkout-total-box"> <h2> {{ calculateTotalWithTax() }}</h2> </div> <div class="checkout-text-box"> <span> Check-Out <i class="fa-solid fa-angle-right"></i> </span> </div> </button> </div> </div> <div v-if="checkoutClicked" class="card"> <div class="card-body"> <div class="payment-info"> <div v-if="formData.payment_type == 'bank'"> <div class="from-group"> <label for="" class="transfer-label">{{ __("custom.account_number") }}</label> <input v-model="formData.bank_info.ac_no" type="text" class="form-control transfer-input" placeholder="Account Number" /> </div> <div class="from-group"> <label for="" class="transfer-label">{{ __("custom.transaction_no") }}</label> <input v-model="formData.bank_info.t_no" type="text" class="form-control transfer-input" placeholder="Transaction No" /> </div> <div class="from-group mt-3 mb-3"> <label for="" class="transfer-label">{{ __("custom.transaction_date") }}</label> <datepicker input-class="form-control" v-model="formData.bank_info.date" format="yyyy-MM-dd"></datepicker> </div> </div> <div v-if="formData.payment_type == 'online'" class="ic-payment-method"> <div class="payment-method mr-1 online-method"> <input v-model="formData.online_type" type="radio" value="paystack" id="paystack" name="online_type" /> <label class="radio-inline radio-image" for="paystack"> <img :src="asset('admin/images/paystack.png')" alt="images" /> </label> </div> <div class="payment-method mr-1 online-method"> <input v-model="formData.online_type" type="radio" value="flutterwave" id="flutterwave" name="online_type" /> <label class="radio-inline radio-image" for="flutterwave"> <img :src="asset('admin/images/flutterwave.png')" class="ic-paypal" alt="images" /> </label> </div> <div class="payment-method mr-1 online-method"> <input v-model="formData.online_type" type="radio" value="other" id="other" name="online_type" /> <label class="radio-inline radio-image other-label" for="other"> + </label> </div> </div> <div class="from-group"> <label for="" class="transfer-label">Input Amount</label> <input v-model="formData.total_paid" type="number" min="0" placeholder="Input Amount" class="form-control amount-input" /> </div> <div class="cta-box"> <button v-if="cartNotEmpty && !invoiceSubmitted" type="button" class="btn btn-dark btn-block tip-btn"> <i class="fa-solid fa-credit-card"></i> <p>Tip Amount</p> </button> <button v-if="cartNotEmpty && invoiceSubmitted" type="button" class="btn btn-dark btn-block tip-btn" @click="openModal"> <i class="fa-solid fa-print"></i> <p>Print Receipt</p> </button> <button v-if="cartNotEmpty" type="button" class="btn btn-dark btn-block done-btn" @click="submitInvoice" :class="{ 'done-btn-submitted': invoiceSubmitted, '': !invoiceSubmitted }" :disabled="invoiceSubmitted"> <i class="fa-solid fa-check"></i> <p>Done</p> </button> </div> </div> </div> </div> <!-- <div class="card"> <div class="card-body"> <div class="col-sm-12 p-0 mt-3"> <div class="col-sm-12 p-0"> <label for="" class="text-muted w-100 mb-0 billing-text">{{ __("custom.billing_info") }} <a class="float-right" href="ic-javascriptVoid" data-toggle="modal" data-target=".billing-info-edit"><i class="fa fa-edit"></i></a></label> </div> <div class="col-sm-12 mt-1 p-0 float-left" v-if="isCustomerSelected || formData.is_walkin_customer"> <p class="m-0">{{ formData.billing.name }}</p> <p class="m-0">{{ formData.billing.email }}</p> <p class="m-0">{{ formData.billing.phone }}</p> <p class="m-0">{{ billinAddressFull() }}</p> </div> </div> <div class="col-sm-12 p-0 mt-3"> <div class="col-sm-12 p-0"> <label for="" class="text-muted mb-0 w-100 billing-text"> {{ __("custom.shipping_info") }} <a class="float-right" href="#" data-toggle="modal" data-target=".shipping-info-edit"><i class="fa fa-edit"></i></a></label> <div class="custom-control custom-checkbox same-box"> <input v-model="is_shipping_same_billing" class="form-check-input custom-control-input" type="checkbox" id="shippingSameBilling" @change="shippingSameBilling($event)" /> <label class="form-check-label custom-control-label checkbox-label walkin-text" for="shippingSameBilling"> {{ __("custom.same_as_billing") }} </label> </div> </div> <div class="col-sm-12 mt-1 p-0" v-if="isCustomerSelected || formData.is_walkin_customer"> <p class="m-0">{{ formData.shipping.name }}</p> <p class="m-0">{{ formData.shipping.email }}</p> <p class="m-0">{{ formData.shipping.phone }}</p> <p class="m-0">{{ shippingAddressFull() }}</p> </div> </div> <div class="from-group mt-3 mb-3"> <label for="" class="label-text">{{ __("custom.date") }}</label> <datepicker input-class="form-control" v-model="formData.date" format="yyyy-MM-dd" placeholder="Select date" v-model.trim="$v.formData.date.$model"></datepicker> <small class="error" v-if="!$v.formData.date.required"> {{ __("custom.required") }} </small> </div> <div class="from-group mt-3 mb-3"> <label for="" class="label-text">{{ __("custom.due_date") }}</label> <datepicker input-class="form-control" v-model="formData.due_date" format="yyyy-MM-dd" placeholder="Select due date"></datepicker> </div> <div class="table-responsive ic-table-responsive-heading"> <table class=" table table-hover table-sm table-borderedless table-striped "> <thead> <tr> <th>{{ __("custom.item") }}</th> <th class="text-center">{{ __("custom.price") }} ({{ currency_symbol }}) </th> <th class="text-center">{{ __("custom.qty") }}</th> <th class="text-center">{{ __("custom.dis") }}</th> <th class="text-center">{{ __("custom.dis_type") }}</th> <th class="text-center">{{ __("custom.sub_total") }}</th> <th class="text-center">{{ __("custom.action") }}</th> </tr> </thead> <tbody> <tr v-for="(item, index) in formData.items" :key="index"> <td> <p class="p-0 m-0" v-if="item.is_variant">{{ item.name }} ({{ item.attribute.name + ':' + item.attribute_item.name }})</p> <p class="p-0 m-0" v-else>{{ item.name }}</p> </td> <td> <input type="number" v-if="item.split_sale" min="1" step="any" v-model="item.price" @input="updatePrice($event, index)" class="form-control text-center border" /> <input type="number" v-else min="1" onkeydown="if(event.key==='.'){event.preventDefault();}" oninput="event.target.value = event.target.value.replace(/[^0-9]*/g,'');" v-model="item.price" @input="updatePrice($event, index)" class="form-control text-center border" /> </td> <td> <input type="number" v-if="item.split_sale" min="1" step="any" v-model="item.quantity" @input="updateQuantity($event, index)" class="form-control text-center border" /> <input type="number" v-else min="1" onkeydown="if(event.key==='.'){event.preventDefault();}" oninput="event.target.value = event.target.value.replace(/[^0-9]*/g,'');" v-model="item.quantity" @input="updateQuantity($event, index)" class="form-control text-center border" /> </td> <td> <input min="0" type="number" v-model="item.discount" class="form-control text-center border" /> </td> <td> <select v-model="item.discount_type" class="form-control border"> <option value="percent">%</option> <option value="fixed">{{ __("custom.fixed") }}</option> </select> </td> <td>{{ currency_symbol }} {{ calculateSubtotal(index) }}</td> <td class="text-center"> <button type="button" class="btn btn-sm btn-outline-danger" @click.prevent="deleteItem(index)"> <i class="fa fa-trash"></i> </button> </td> </tr> </tbody> <tfoot> <tr> <td colspan="5"> <b>{{ __("custom.sub_total") }}</b> </td> <td> <b>{{ currency_symbol }} {{ calculateTotalWithOutTax() }}</b> </td> <td></td> </tr> <tr v-if="cartNotEmpty"> <td colspan="2"> <b>{{ __("custom.discount") }}</b> </td> <td> <input type="number" v-model="formData.discount" class="form-control text-center border" /> </td> <td colspan="2"> <select v-model="formData.discount_type" class="form-control text-center border"> <option value="percent">%</option> <option value="fixed">{{ __("custom.fixed") }}</option> </select> </td> <td> <b>{{ currency_symbol }} {{ calculateGlobalDiscount() }}</b> </td> <td></td> </tr> <tr v-if="cartNotEmpty"> <td colspan="5"> <b>{{ __("custom.total_discount") }}</b> </td> <td> <b>{{ currency_symbol }} {{ calculateTotalDiscount() }}</b> </td> <td></td> </tr> <tr> <td colspan="5"> <b>{{ __("custom.tax") }}</b> </td> <td> <b>{{ currency_symbol }} {{ totalTax() }}</b> </td> <td></td> </tr> <tr> <td colspan="5"> <b>{{ __("custom.total") }}</b> </td> <td> <b>{{ currency_symbol }} {{ calculateTotalWithTax() }}</b> </td> <td></td> </tr> </tfoot> </table> </div> <div class="form-grou"> <div class="row"> <div class="col-8"> <label for="">{{ __("custom.coupon") }}</label> <input class="form-control input-sm" name="coupon" v-model="formData.coupon.code" /> </div> <div class="col-4"> <label for=""> </label> <button type="button" class="btn btn-primary btn-block btn-sm" @click="applyCoupon"> {{ __("custom.apply") }} </button> </div> </div> </div> <div class="col-sm-12 p-0"> <label for="" class="w-100">{{ __("custom.payment") }}</label> <div class="ic-payment-method"> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="cash" id="cash" name="payment_type" /> <label class="radio-inline radio-image" for="cash"> <span></span> <img :src="asset('admin/images/cash.png')" alt="images" /> </label> </div> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="online" id="online" name="payment_type" /> <label class="radio-inline radio-image" for="online"> <span></span> <img :src="asset('admin/images/online.png')" class="ic-paypal" alt="images" /> </label> </div> <div class="payment-method mr-1"> <input v-model="formData.payment_type" type="radio" value="bank" id="bank" name="payment_type" /> <label class="radio-inline radio-image" for="bank"> <span></span> <img :src="asset('admin/images/bank.png')" class="ic-paypal" alt="images" /> </label> </div> </div> <div class="from-group"> <label for="">{{ __("custom.total_paid") }}</label> <input v-model="formData.total_paid" type="number" min="0" class="form-control" /> </div> <div v-if="formData.payment_type == 'bank'"> <div class="from-group"> <label for="">{{ __("custom.account_number") }}</label> <input v-model="formData.bank_info.ac_no" type="text" class="form-control" /> </div> <div class="from-group"> <label for="">{{ __("custom.transaction_no") }}</label> <input v-model="formData.bank_info.t_no" type="text" class="form-control" /> </div> <div class="from-group mt-3 mb-3"> <label for="">{{ __("custom.transaction_date") }}</label> <datepicker input-class="form-control" v-model="formData.bank_info.date" format="yyyy-MM-dd"></datepicker> </div> </div> </div> <div class="form-grou"> <label for="">{{ __("custom.note") }}</label> <textarea v-model="formData.notes" cols="30" rows="10" class="form-control"></textarea> </div> <div class="col-sm-12 p-0 mt-3" v-if="cartNotEmpty"> <div class="custom-control custom-checkbox"> <input name="is_delivered" v-model="formData.is_delivered" class="form-check-input custom-control-input" type="checkbox" checked="checked" id="is_delivered" /> <label class="form-check-label custom-control-label checkbox-label" for="is_delivered"> {{ __("custom.is_delivered") }} </label> </div> </div> <div class="col-sm-12 p-0 mt-3"> <div class="text-center"> <button v-if="cartNotEmpty" type="button" class="btn btn-dark btn-block" @click="submitInvoice"> {{ __("custom.confirm") }} </button> <button class="btn btn-link float-right" v-if="cartNotEmpty" @click="resetAllValues"><i class="fas fa-redo"></i> {{ __("custom.reset") }} </button> </div> </div> </div> </div> --> </div> <!-- Billing info edit modal --> <div class="modal fade billing-info-edit" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{{ __("custom.billing_info") }}</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.name") }}</label> <input type="text" class="form-control" v-model="formData.billing.name" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.email") }}</label> <input type="email" class="form-control" v-model="formData.billing.email" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.phone") }}</label> <input type="text" class="form-control" v-model="formData.billing.phone" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.address_line_1") }}</label> <input type="text" class="form-control" v-model="formData.billing.address_line_1" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.address_line_2") }}</label> <input type="text" class="form-control" v-model="formData.billing.address_line_2" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.city") }}</label> <input type="text" class="form-control" v-model="formData.billing.city" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.state") }}</label> <input type="text" class="form-control" v-model="formData.billing.state" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.zipcode") }}</label> <input type="text" class="form-control" v-model="formData.billing.zip" /> </div> </div> <div class="col-sm-4"> <div class="form-group"> <label for="">{{ __("custom.country") }}</label> <input type="text" class="form-control" v-model="formData.billing.country" /> </div> </div> </div> </div> <div class="modal-footer text-right"> <button type="button" class="btn btn-primary" data-dismiss="modal"> {{ __("custom.save_and_close") }} </button> </div> </div> </div> </div> <!-- Shipping info edit modal --> <div class="modal fade shipping-info-edit" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel1" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{{ __("custom.shipping_info") }}</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="row"> <div class="col-sm-4"> <label for="">{{ __("custom.name") }}</label> <input type="text" class="form-control" v-model="formData.shipping.name" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.email") }}</label> <input type="email" class="form-control" v-model="formData.shipping.email" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.phone") }}</label> <input type="text" class="form-control" v-model="formData.shipping.phone" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.address_line_1") }}</label> <input type="text" class="form-control" v-model="formData.shipping.address_line_1" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.address_line_2") }}</label> <input type="text" class="form-control" v-model="formData.shipping.address_line_2" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.city") }}</label> <input type="text" class="form-control" v-model="formData.shipping.city" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.state") }}</label> <input type="text" class="form-control" v-model="formData.shipping.state" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.post_code_or_zip_code") }}</label> <input type="text" class="form-control" v-model="formData.shipping.zip" /> </div> <div class="col-sm-4"> <label for="">{{ __("custom.country") }}</label> <input type="text" class="form-control" v-model="formData.shipping.country" /> </div> </div> </div> <div class="modal-footer text-right"> <button type="button" class="btn btn-primary" data-dismiss="modal"> {{ __("custom.save_and_close") }} </button> </div> </div> </div> </div> </div> </div> </div> </template> <script> import moment from "moment"; import axios from "axios"; import Datepicker from "vuejs-datepicker"; import { required } from "vuelidate/lib/validators"; export default { props: [ "app_name", "product_stocks", "categories", "customers", "user", "default_tax", "warehouse_id", "currency_symbol", "organisation" ], components: { Datepicker, }, data() { return { validationErrors: [], isExistsValidationErrors: 0, currencySymbol: "", product_list: {}, selected_category: "all", search: "", char_limit: 200, isModalOpen: false, emailReceiptEnabled: false, // Toggle for email receipt printReceiptEnabled: false, // Toggle for print receipt receiptCount: 1, // Number of receipts isPrinting: false, is_shipping_same_billing: false, formData: { warehouse_id: this.warehouse_id, payment_type: "cash", is_walkin_customer: false, is_delivered: true, walkin_customer: { full_name: "", phone: "", }, bank_info: { ac_no: "", t_no: "", date: "", }, date: "", due_date: "", customer_id: "", billing: { name: "", email: "", phone: "", address_line_1: "", address_line_2: "", city: "", state: "", zip: "", country: "", }, shipping: { name: "", email: "", phone: "", address_line_1: "", address_line_2: "", city: "", state: "", zip: "", country: "", }, items: [], status: "", notes: "", tax: 0, discount: 0, discount_type: "", // percent, fixed total_paid: 0, coupon: { code: "", discount: 0, discount_type: "percent", // percent, fixed }, }, checkoutClicked: false, invoiceSubmitted: false, organisationData: {}, currentDate: this.getCurrentDate(), }; }, mounted() { this.formData.date = new Date().toISOString(); this.formData.due_date = new Date().toISOString(); this.product_list = this.product_stocks; this.organisationData = this.organisation; console.log(this.organisationData) // Update the date every minute setInterval(() => { this.currentDate = this.getCurrentDate(); }, 60000); // 60000ms = 1 minute }, computed: { showProduct: function () { return this.product_stocks.length > 0 ? true : false; }, cartNotEmpty: function () { return this.formData.items.length; }, charactersLeft() { let char = this.form.note.length; return this.char_limit - char + " / " + this.char_limit; }, isCustomerSelected: function () { if (this.formData.customer_id) { return true; } else { return false; } }, }, methods: { openModal() { this.isModalOpen = true; }, closeModal() { this.isModalOpen = false; }, incrementReceiptCount() { this.receiptCount += 1; }, decrementReceiptCount() { if (this.receiptCount > 1) { this.receiptCount -= 1; } }, getCurrentDate() { const now = new Date(); const options = { weekday: 'short', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }; return now.toLocaleDateString('en-US', options); // Format the date }, printReceipt() { // Simply set the flag to true to display the printable version this.isPrinting = true; // Use nextTick to ensure the component has updated this.$nextTick(() => { // Trigger browser print window.print(); // Add listener to reset the state after printing is done window.addEventListener('afterprint', () => { this.isPrinting = false; }, { once: true }); }); }, getImageUrl(image) { return image ? `${image}` : "/images/default-64.png"; }, handleImageError(event) { // Replace the broken image with a default image event.target.src = "/images/default-64.png"; // Path to your default image }, resetAllValues() { window.location.replace(location.href) }, searchSelectSku(e) { let query = e.target.value; if (query.length > 1) { // Search product by sku axios .get(`/admin/app/api/product-stocks/name-sku/search/${query}/${this.warehouse_id}`) .then((res) => { this.product_list = res.data.data; }) .catch((err) => { }); } else if (query.length == 0) { let warehouse_id = this.warehouse_id; axios .get(`/admin/app/api/product-stocks/warehouse/search/${warehouse_id}`) .then((res) => { this.product_list = res.data.data; }) .catch((err) => { }); // this.searched_product = []; } else { this.searched_product = []; } }, submitBarcode() { axios .get(`/admin/app/api/product-stocks/barcode/${this.search}`) .then((res) => { let product_stock = res.data.data; if (product_stock) { if (product_stock.quantity < 1) { this.$swal("Error!!!", `Out of stock`, "warning"); // Empty search field this.search = ""; return; } if (product_stock.product.is_variant == 0) { let already_added = this.formData.items.find( (i) => i.id == product_stock.id ); if (already_added) { already_added.quantity = already_added.quantity + 1; } else { if (product_stock.product.is_variant == 1) { this.formData.items.push({ id: product_stock.id, attribute: { id: product_stock.attribute.id, name: product_stock.attribute.name, }, attribute_item: { id: product_stock.attribute_item.id, name: product_stock.attribute_item.name, }, is_variant: product_stock.product.is_variant, product_id: product_stock.product.id, split_sale: product_stock.product.split_sale, sku: product_stock.product.sku, name: product_stock.product.name, price: product_stock.price_for_sale, stock: product_stock.quantity, quantity: 1, tax_status: product_stock.product.tax_status, custom_tax: product_stock.product.custom_tax, discount: 0, discount_type: "percent", }); } else { this.formData.items.push({ id: product_stock.id, attribute: { id: '', name: '', }, attribute_item: { id: '', name: '', }, is_variant: product_stock.product.is_variant, product_id: product_stock.product.id, split_sale: product_stock.product.split_sale, sku: product_stock.product.sku, name: product_stock.product.name, price: product_stock.price_for_sale, stock: product_stock.quantity, quantity: 1, tax_status: product_stock.product.tax_status, custom_tax: product_stock.product.custom_tax, discount: 0, discount_type: "percent", }); } } let warehouse_id = this.warehouse_id; axios .get(`/admin/app/api/product-stocks/warehouse/search/${warehouse_id}`) .then((res) => { this.product_list = res.data.data; }) .catch((err) => { }); this.search = ""; } } else { // this.$swal("info!!!", `Please select variant`, "info"); this.product_list = res.data.data; } }) .catch((err) => { }); // Empty search field }, selectCategory({ id }) { axios .get(`/admin/app/api/product-stocks/category/${id}/${this.warehouse_id}`) .then((res) => { this.product_list = res.data.data; }) .catch((err) => { }); }, shippingSameBilling(e) { if (this.is_shipping_same_billing) { this.formData.shipping.name = this.formData.billing.name; this.formData.shipping.email = this.formData.billing.email; this.formData.shipping.phone = this.formData.billing.phone; this.formData.shipping.address_line_1 = this.formData.billing.address_line_1; this.formData.shipping.address_line_2 = this.formData.billing.address_line_2; this.formData.shipping.city = this.formData.billing.city; this.formData.shipping.state = this.formData.billing.state; this.formData.shipping.zip = this.formData.billing.zip; this.formData.shipping.country = this.formData.billing.country; } }, billinAddressFull() { let { address_line_1, address_line_2, city, state, zip, country } = this.formData.billing; return `${address_line_1}, ${address_line_2}, ${city}, ${state}, ${zip}, ${country}`; }, shippingAddressFull() { let { address_line_1, address_line_2, city, state, zip, country } = this.formData.shipping; return `${address_line_1}, ${address_line_2}, ${city}, ${state}, ${zip}, ${country}`; }, selectedCustomer({ id }) { let customer = this.customers.find((item) => item.id == id); // Set billing address this.formData.billing = { name: customer.full_name, email: customer.email, phone: customer.b_phone, address_line_1: customer.b_address_line_1, address_line_2: customer.b_address_line_2, city: customer.b_city_data ? customer.b_city_data.name : "", state: customer.b_state_data ? customer.b_state_data.name : "", zip: customer.b_zipcode, country: customer.b_country_data ? customer.b_country_data.name : "", }; }, addNewItem(product_stock) { let found = this.formData.items.findIndex((p) => p.id == product_stock.id); if (found >= 0) { let item = this.formData.items[found]; if (item.quantity >= product_stock.quantity) { item.quantity = product_stock.quantity; this.$swal("Error!!!", `Out of stock`, "warning"); // Empty search field this.search = ""; return; } item.quantity = Number(item.quantity) + 1; } else { if (product_stock.quantity < 1) { this.$swal("Error!!!", `Out of stock`, "warning"); // Empty search field this.search = ""; return; } if (product_stock.product.is_variant == 1) { this.formData.items.push({ id: product_stock.id, attribute: { id: product_stock.attribute.id, name: product_stock.attribute.name, }, attribute_item: { id: product_stock.attribute_item.id, name: product_stock.attribute_item.name, }, is_variant: product_stock.product.is_variant, product_id: product_stock.product.id, split_sale: product_stock.product.split_sale, sku: product_stock.product.sku, name: product_stock.product.name, price: product_stock.price_for_sale, stock: product_stock.quantity, quantity: 1, tax_status: product_stock.product.tax_status, custom_tax: product_stock.product.custom_tax, discount: 0, discount_type: "percent", }); } else { this.formData.items.push({ id: product_stock.id, attribute: { id: '', name: '', }, attribute_item: { id: '', name: '', }, is_variant: product_stock.product.is_variant, product_id: product_stock.product.id, split_sale: product_stock.product.split_sale, sku: product_stock.product.sku, name: product_stock.product.name, price: product_stock.price_for_sale, stock: product_stock.quantity, quantity: 1, tax_status: product_stock.product.tax_status, custom_tax: product_stock.product.custom_tax, discount: 0, discount_type: "percent", }); } } }, deleteItem: function (index) { this.formData.items.splice(index, 1); }, updatePrice(event, index) { const value = event.target.valueAsNumber; let item = this.formData.items[index]; }, increaseQuantity(index) { let item = this.formData.items[index]; if (item.quantity < item.stock) { item.quantity++; } else { this.$swal("Error!!!", `Out of stock`, "warning"); } }, decreaseQuantity(index) { let item = this.formData.items[index]; if (item.quantity > 1) { item.quantity--; } }, updateQuantity(event, index) { const value = event.target.valueAsNumber; let item = this.formData.items[index]; if (value > item.stock) { item.quantity = item.stock; this.$swal("Error!!!", `Out of stock`, "warning"); return; } }, formatCurrency(amount) { if (isNaN(amount) || amount === null) return "₦0.00"; return new Intl.NumberFormat("en-NG", { style: "currency", currency: "NGN", minimumFractionDigits: 2, }).format(amount); }, calculateSubtotal(index) { let item = this.formData.items[index]; const unitPrice = (item.customer_buying_price && item.customer_buying_price > 0) ? item.customer_buying_price : item.price; const total = item.quantity * (unitPrice - this.calculateDiscount(item)); return this.formatCurrency(total); }, calculateTotalWithOutTax() { const total = this.itemsTotal() - this.totalTax(); // console.log(this.itemsTotal()); // console.log(this.totalTax()); //return Number(total).toFixed(2); return this.formatCurrency(Number(total)); }, calculateTotalWithTax() { const total = this.itemsTotal() - this.calculateGlobalDiscount(); //return Number(total).toFixed(2); return this.formatCurrency(Number(total)); }, itemsTotal() { if (this.formData.items.length > 0) { let total = 0; this.formData.items.map((item) => { // console.log(this.calculateTax(item)); total = (Number(item.price - this.calculateDiscount(item)) + Number(this.calculateTax(item))) * item.quantity + Number(total); }); return total.toFixed(2); } return 0; }, totalTax() { let total = 0; this.formData.items.map((item) => { total = Number(this.calculateTax(item)) * item.quantity + Number(total); }); return total.toFixed(2); }, calculateTax(item) { let tax = 0; // Tax include if (item.tax_status == "included") { if (item.custom_tax) { tax = item.price * (item.custom_tax / 100); } else { tax = item.price * (Number(this.default_tax) / 100); } } return tax; }, calculateDiscount(item) { if (item.discount_type == "percent") { const total = item.price * (item.discount / 100); return total.toFixed(2); } else { return item.discount; } }, calculateGlobalDiscount() { if (this.formData.discount_type == "percent") { const total = this.calculateTotalWithOutTax() * (this.formData.discount / 100); return total.toFixed(2); } else { return this.formData.discount; } }, calculateAllDiscount() { let total = 0; this.formData.items.map((item) => { total += item.quantity * this.calculateDiscount(item); }); return total.toFixed(2); }, calculateTotalDiscount() { let total = 0; this.formData.items.map((item) => { total += item.quantity * this.calculateDiscount(item); }); if (Number(this.formData.discount) > 0) { total = Number(total) + Number(this.calculateGlobalDiscount()); } return Number(total).toFixed(2); }, calculateDue() { let due = this.calculateTotalWithOutTax() - this.formData.total_paid; if (due <= 0) return 0; return due.toFixed(2); }, calculateExchange() { let exchange = this.formData.total_paid - this.calculateTotalWithOutTax(); if (exchange > 0) { this.form.exchange = exchange; return exchange.toFixed(2); } else { this.form.exchange = 0; return false; } }, submitInvoice() { if (this.formData.payment_type != "bank") { axios .post("/admin/invoices", this.formData) .then((res) => { // window.location.href = "/admin/invoices/" + res.data.invoice; this.invoiceSubmitted = true; }) .catch(err => { if (err.response.data.success == false) { this.isExistsValidationErrors = 0 this.$swal("Error!!!", "Some thing went wrong!", "error"); } else { this.validationErrors = err.response.data this.isExistsValidationErrors = Object.keys(this.validationErrors.errors).length this.$swal("Error!!!", "Some thing went wrong!", "error"); } }); } else if (this.formData.payment_type == "bank" && this.formData.bank_info.ac_no != "" && this.formData.bank_info.t_no != "" && this.formData.bank_info.date != "") { axios .post("/admin/invoices", this.formData) .then((res) => { // window.location.href = "/admin/invoices/" + res.data.invoice; this.invoiceSubmitted = true; }) .catch((err) => { if (err.response.data.success == false) { this.isExistsValidationErrors = 0 this.$swal("Error!!!", "Some thing went wrong!", "error"); } else { this.validationErrors = err.response.data this.isExistsValidationErrors = Object.keys(this.validationErrors.errors).length this.$swal("Error!!!", "Some thing went wrong!", "error"); } }); } else { alert("Please fill up all this three (Account Number, Transaction No, Transaction Date) field!") } }, print() { this.$htmlToPaper("invoice-print"); }, applyCoupon() { if (this.formData.coupon.code) { axios .get("/admin/app/api/active-coupon/" + this.formData.coupon.code) .then((res) => { let available_product = false; if (res.data.status == true) { let coupon_product_ids = res.data.coupon_product_ids; for (let i = 0; i < this.formData.items.length; i++) { if (coupon_product_ids.find(id => id == this.formData.items[i].product_id)) { if (this.formData.items[i].quantity >= res.data.coupon.minimum_shopping) { this.formData.items[i].discount = res.data.coupon.discount; this.formData.items[i].discount_type = res.data.coupon.discount_type; available_product = true; } } } this.formData.coupon.discount = res.data.coupon.discount; this.formData.coupon.discount_type = res.data.coupon.discount_type; this.$swal("Success!", "Coupon applied successfully!", "success"); if (available_product == false) { this.$swal("Error!!!", "This coupon is not applicable for this product!", "error"); } else { this.$swal("Success!!!", "Coupon applied successfully!", "success"); } } else { this.$swal("Error!!!", "Some thing went wrong! Maybe coupon expire or invalid", "error"); } }) .catch((err) => { this.$swal("Error!!!", "Some thing went wrong!", "error"); }); } }, btnWalkinCustomer() { this.formData.walkin_customer.full_name = ''; this.formData.walkin_customer.phone = ''; this.formData.customer_id = ''; this.formData.billing.name = ''; this.formData.billing.email = ''; this.formData.billing.phone = ''; this.formData.billing.address_line_1 = ''; this.formData.billing.address_line_2 = ''; this.formData.billing.city = ''; this.formData.billing.state = ''; this.formData.billing.zip = ''; this.formData.billing.country = ''; this.formData.shipping.name = ''; this.formData.shipping.email = ''; this.formData.shipping.phone = ''; this.formData.shipping.address_line_1 = ''; this.formData.shipping.address_line_2 = ''; this.formData.shipping.city = ''; this.formData.shipping.state = ''; this.formData.shipping.zip = ''; this.formData.shipping.country = ''; }, handleCheckout() { this.checkoutClicked = true; }, truncateText(text, limit) { if (!text) return ''; return text.length > limit ? text.slice(0, limit) + "..." : text; } }, filters: { custom_date: function (value) { if (value) { return moment(String(value)).format("YYYY-MM-DD hh:mm a"); } }, }, validations: { formData: { date: { required, }, customer_id: { required, }, status: { required, }, }, }, }; </script> <style scoped> .new-design-input .form-control { border-radius: 20px; border: 1px solid #ccc; padding: 10px 15px; font-size: 14px; } .new-design-select .select2-container { width: 100% !important; } .new-design-select .select2-selection { border-radius: 20px; border: 1px solid #ccc; padding: 5px 10px; height: 40px; line-height: 30px; } .new-design-select .select2-selection__arrow { height: 38px; } .category-buttons { display: flex; gap: 10px; flex-wrap: wrap; } .category-buttons button { display: flex; align-items: center; gap: 8px; padding: 10px 15px; border: none; outline: none; cursor: pointer; transition: background-color 0.3s ease; background-color: #f5f5f5; } .category-buttons button.active { background-color: #007bff; color: white; border-color: #007bff; } .category-buttons button:hover { background-color: #e9ecef; } .category-image { width: 20px; height: 20px; object-fit: contain; } .category-name { font-size: 14px; } .list-image { height: 100px; object-fit: cover; object-position: center; } .product-item:hover { cursor: pointer; } /* Modal Overlay */ .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } /* Modal Content */ .modal-content { background-color: white; border-radius: 8px; width: 500px; padding: 20px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } /* Modal Header */ .modal-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #ddd; padding-bottom: 10px; margin-bottom: 15px; } .modal-header h2 { margin: 0; font-size: 20px; } .close-button { background: none; border: none; font-size: 24px; cursor: pointer; color: #666; } .close-button:hover { color: #000; } /* Modal Body */ .modal-body { margin-bottom: 15px; } .modal-body p { margin: 10px 0; } /* Toggle Options */ .toggle-option { display: flex; justify-content: space-between; align-items: center; margin: 15px 0; } .switch { position: relative; display: inline-block; width: 50px; height: 24px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: 0.4s; border-radius: 24px; } .slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 2px; bottom: 2px; background-color: white; transition: 0.4s; border-radius: 50%; } input:checked+.slider { background-color: #007bff; } input:checked+.slider:before { transform: translateX(26px); } /* Number Counter */ .number-counter { display: flex; justify-content: space-between; align-items: center; margin: 15px 0; } .counter-controls { display: flex; align-items: center; } .counter-button { padding: 5px 10px; background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; transition: background-color 0.3s ease; } .counter-button:hover { background-color: #e9ecef; } .counter-input { width: 50px; text-align: center; margin: 0 10px; padding: 5px; border: 1px solid #ddd; border-radius: 4px; } /* Modal Footer */ .modal-footer-b { display: flex; justify-content: center; gap: 10px; border-top: 1px solid #ddd; padding-top: 15px; } .cancel-button { padding: 10px 60px; background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; transition: background-color 0.3s ease; } .cancel-button:hover { background-color: #e9ecef; } .print-button { padding: 10px 60px; background-color: #012060; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s ease; } .print-button:hover { background-color: #012060; } .modal-footer { display: -ms-flexbox; display: block; -ms-flex-align: center; align-items: center; -ms-flex-pack: end; justify-content: flex-end; padding: 1rem; border-top: 1px solid #dee2e6; border-bottom-right-radius: 0.3rem; border-bottom-left-radius: 0.3rem; } /* Receipt Styling */ .printable-content { font-family: 'Arial', sans-serif; max-width: 380px; margin: 0 auto; padding: 20px; background-color: white; color: #333; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); display: none; /* Hidden by default, only shown when printing */ } /* Header with dark blue background */ .receipt-header { background-color: #1a2b5e; color: white; text-align: center; padding: 15px; margin: -20px -20px 15px; } .receipt-header h1 { margin: 0 0 10px; font-size: 20px; font-weight: bold; } .receipt-header p { margin: 2px 0; font-size: 14px; } /* Transaction details */ .receipt-details { border-bottom: 1px solid #eee; padding-bottom: 10px; margin-bottom: 10px; } .receipt-details p { margin: 5px 0; display: flex; justify-content: space-between; font-size: 14px; } /* Summary section */ .receipt-summary { border-bottom: 1px solid #eee; padding-bottom: 10px; margin-bottom: 10px; } .receipt-summary p { margin: 5px 0; display: flex; justify-content: space-between; font-size: 14px; } /* Items table */ .receipt-items { margin-bottom: 15px; } .receipt-items h3 { margin-bottom: 10px; font-size: 16px; } .receipt-items table { width: 100%; border-collapse: collapse; } .receipt-items th { text-align: left; border-bottom: 1px solid #ddd; padding: 8px 4px; font-size: 14px; } .receipt-items td { padding: 8px 4px; border-bottom: 1px solid #eee; font-size: 14px; } /* Payment information */ .receipt-payment { border-bottom: 1px solid #eee; padding-bottom: 10px; margin-bottom: 10px; } .receipt-payment p { margin: 5px 0; font-size: 14px; } /* Footer */ .receipt-footer { text-align: center; margin-top: 20px; font-size: 14px; } .receipt-footer p:last-child { font-weight: bold; margin-top: 10px; font-size: 16px; } /* Print button styling */ .print-btn { background-color: #1a2b5e; color: white; border: none; padding: 10px 20px; font-size: 16px; cursor: pointer; border-radius: 4px; margin: 20px 0; } .print-btn:hover { background-color: #121e42; } /* Total amount highlight */ .total-amount { font-weight: bold; font-size: 16px; } /* Print media query */ @media print { body * { visibility: hidden; } .printable-content, .printable-content * { visibility: visible; display: block; } .printable-content { position: absolute; left: 0; top: 0; width: 100%; box-shadow: none; } .no-print { display: none !important; } } </style>
| ver. 1.4 |
Github
|
.
| PHP 8.3.30 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings