Skip to content
Open

jack #488

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions posawesome/posawesome/api/posapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ def update_invoice_from_order(data):
invoice_doc.save()
return invoice_doc


#update def
@frappe.whitelist()
def update_invoice(data):
data = json.loads(data)
Expand All @@ -501,6 +501,12 @@ def update_invoice(data):
else:
invoice_doc = frappe.get_doc(data)

# FIX: Bersihkan nilai 'Nothing' yang salah dari give_item di POS Offer
if hasattr(invoice_doc, "posa_offers"):
for offer in invoice_doc.posa_offers:
if offer.get("give_item") == "Nothing":
offer.give_item = None

invoice_doc.set_missing_values()
invoice_doc.flags.ignore_permissions = True
frappe.flags.ignore_account_permission = True
Expand All @@ -517,6 +523,7 @@ def update_invoice(data):
for payment in invoice_doc.payments:
if payment.default:
payment.amount = invoice_doc.paid_amount

allow_zero_rated_items = frappe.get_cached_value(
"POS Profile", invoice_doc.pos_profile, "posa_allow_zero_rated_items"
)
Expand Down Expand Up @@ -550,7 +557,6 @@ def update_invoice(data):
invoice_doc.save()
return invoice_doc


@frappe.whitelist()
def submit_invoice(invoice, data):
data = json.loads(data)
Expand Down
27 changes: 15 additions & 12 deletions posawesome/public/js/posapp/components/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
></v-app-bar-nav-icon>
<v-img
src="/assets/posawesome/js/posapp/components/pos/pos.png"
alt="POS Awesome"
alt="GCG Reparo"
max-width="32"
class="mr-2"
color="primary"
Expand All @@ -17,8 +17,8 @@
style="cursor: pointer"
class="text-uppercase primary--text"
>
<span class="font-weight-light">pos</span>
<span>awesome</span>
<span class="font-weight-light">gcg</span>
<span>Reparo</span>
</v-toolbar-title>

<v-spacer></v-spacer>
Expand Down Expand Up @@ -157,7 +157,7 @@ export default {
snack: false,
snackColor: '',
snackText: '',
company: 'POS Awesome',
company: 'GCG Reparo',
company_img: '/assets/erpnext/images/erpnext-logo.svg',
pos_profile: '',
freeze: false,
Expand Down Expand Up @@ -192,15 +192,18 @@ export default {
logOut() {
var me = this;
me.logged_out = true;
// Panggil metode logout dari server
return frappe.call({
method: 'logout',
callback: function (r) {
if (r.exc) {
return;
}
frappe.set_route('/login');
location.reload();
},
method: 'logout',
callback: function (r) {
if (r.exc) {
console.error('Logout error:', r.exc);
return;
}

// Redirect manual ke halaman /reparo-front
window.location.href = '/reparo-front';
},
});
},
print_last_invoice() {
Expand Down
219 changes: 131 additions & 88 deletions posawesome/public/js/posapp/components/pos/Customer.vue
Original file line number Diff line number Diff line change
@@ -1,136 +1,159 @@
<template>
<div>
<v-autocomplete
:key="autocompleteKey"
dense
clearable
auto-select-first
outlined
color="primary"
:label="frappe._('Customer')"
v-model="customer"
:items="customers"
item-text="customer_name"
item-value="name"
v-model="selectedCustomer"
:items="processedCustomers"
item-text="display_name"
item-value="unique_key"
background-color="white"
:no-data-text="__('Customer not found')"
hide-details
:filter="customFilter"
:disabled="readonly"
append-icon="mdi-plus"
append-icon="mdi-account-plus"
@click:append="new_customer"
prepend-inner-icon="mdi-account-edit"
prepend-inner-icon="mdi-car-multiple"
@click:prepend-inner="edit_customer"
>
<template v-slot:item="data">
<template>
<v-list-item-content>
<v-list-item-title
class="primary--text subtitle-1"
v-html="data.item.customer_name"
></v-list-item-title>
<v-list-item-subtitle
v-if="data.item.customer_name != data.item.name"
v-html="`ID: ${data.item.name}`"
></v-list-item-subtitle>
<v-list-item-subtitle
v-if="data.item.tax_id"
v-html="`TAX ID: ${data.item.tax_id}`"
></v-list-item-subtitle>
<v-list-item-subtitle
v-if="data.item.email_id"
v-html="`Email: ${data.item.email_id}`"
></v-list-item-subtitle>
<v-list-item-subtitle
v-if="data.item.mobile_no"
v-html="`Mobile No: ${data.item.mobile_no}`"
></v-list-item-subtitle>
<v-list-item-subtitle
v-if="data.item.primary_address"
v-html="`Primary Address: ${data.item.primary_address}`"
></v-list-item-subtitle>
</v-list-item-content>
</template>
<template v-slot:item="{ item }">
<v-list-item-content>
<v-list-item-title class="primary--text subtitle-1">
{{ item.display_name || 'NO DISPLAY NAME' }}
</v-list-item-title>
<v-list-item-subtitle v-if="item.license_plate">
License Plate: {{ item.license_plate }}
</v-list-item-subtitle>
<v-list-item-subtitle v-if="item.mobile_no">
Mobile No: {{ item.mobile_no }}
</v-list-item-subtitle>
</v-list-item-content>
</template>
</v-autocomplete>
<div class="mb-8">
<UpdateCustomer></UpdateCustomer>
<UpdateCustomer />
</div>
</div>
</template>

<script>
import { evntBus } from '../../bus';
import UpdateCustomer from './UpdateCustomer.vue';
import { evntBus } from "../../bus";
import UpdateCustomer from "./UpdateCustomer.vue";

export default {
data: () => ({
pos_profile: '',
customers: [],
customer: '',
readonly: false,
customer_info: {},
}),
data() {
return {
pos_profile: "",
customers: [],
selectedCustomer: "", // Menyimpan customer_id saja
autocompleteKey: 0,
readonly: false,
customer_info: {},
};
},

components: {
UpdateCustomer,
},

computed: {
processedCustomers() {
let processed = [];
console.log("Data Customers:", this.customers);

this.customers.forEach((customer) => {
if (customer.vehicles && customer.vehicles.length > 0) {
customer.vehicles.forEach((vehicle) => {
processed.push({
customer_id: customer.name, // Hanya simpan customer.name
customer_name: customer.customer_name,
display_name: `${customer.customer_name} : ${vehicle.license_plate}`,
license_plate: vehicle.license_plate,
mobile_no: customer.mobile_no || "N/A",
unique_key: `${customer.name}_${vehicle.license_plate}`, // Buat kombinasi unik
});
});
} else {
processed.push({
customer_id: customer.name, // Hanya simpan customer.name
customer_name: customer.customer_name,
display_name: customer.customer_name,
license_plate: null,
mobile_no: customer.mobile_no || "N/A",
unique_key: `${customer.name}_no_license`, // Unik meskipun tanpa kendaraan
});
}
});

console.log("Processed Customers:", processed);
return processed;
},
},

methods: {
get_customer_names() {
const vm = this;
if (this.customers.length > 0) {
return;
}
if (vm.pos_profile.posa_local_storage && localStorage.customer_storage) {
vm.customers = JSON.parse(localStorage.getItem('customer_storage'));
if (this.customers.length > 0) return;

if (this.pos_profile.posa_local_storage && localStorage.customer_storage) {
try {
this.customers = JSON.parse(localStorage.getItem("customer_storage"));
} catch (e) {
console.error("Error parsing customer_storage:", e);
}
}

frappe.call({
method: 'posawesome.posawesome.api.posapp.get_customer_names',
method: "reparo.api.customer.get_customer_names",
args: {
pos_profile: this.pos_profile.pos_profile,
},
callback: function (r) {
if (r.message) {
vm.customers = r.message;
console.info('loadCustomers');
if (vm.pos_profile.posa_local_storage) {
localStorage.setItem('customer_storage', '');
localStorage.setItem(
'customer_storage',
JSON.stringify(r.message)
);
callback: (r) => {
console.log("API Response:", r.message);
if (r.message && Array.isArray(r.message)) {
this.$set(this, "customers", [...r.message]); // Paksa Vue mengenali perubahan
if (this.pos_profile.posa_local_storage) {
localStorage.setItem("customer_storage", JSON.stringify(r.message));
}
} else {
console.error("Invalid response format:", r);
}
},
});
},

new_customer() {
evntBus.$emit('open_update_customer', null);
evntBus.$emit("open_update_customer", null);
this.$nextTick(() => {
this.$set(this, "selectedCustomer", "");
this.autocompleteKey++;
});
},

edit_customer() {
evntBus.$emit('open_update_customer', this.customer_info);
evntBus.$emit("open_update_customer", this.customer_info);
this.$nextTick(() => {
this.$set(this, "selectedCustomer", "");
this.autocompleteKey++;
});
},
customFilter(item, queryText, itemText) {
const textOne = item.customer_name
? item.customer_name.toLowerCase()
: '';
const textTwo = item.tax_id ? item.tax_id.toLowerCase() : '';
const textThree = item.email_id ? item.email_id.toLowerCase() : '';
const textFour = item.mobile_no ? item.mobile_no.toLowerCase() : '';
const textFifth = item.name.toLowerCase();
const searchText = queryText.toLowerCase();

customFilter(item, queryText) {
if (!queryText) return true;
const searchText = queryText.toLowerCase();
return (
textOne.indexOf(searchText) > -1 ||
textTwo.indexOf(searchText) > -1 ||
textThree.indexOf(searchText) > -1 ||
textFour.indexOf(searchText) > -1 ||
textFifth.indexOf(searchText) > -1
item.customer_name.toLowerCase().includes(searchText) ||
(item.license_plate && item.license_plate.toLowerCase().includes(searchText)) ||
(item.mobile_no && item.mobile_no.toLowerCase().includes(searchText))
);
},
},

computed: {},

created: function () {
this.$nextTick(function () {
evntBus.$on('register_pos_profile', (pos_profile) => {
Expand All @@ -141,27 +164,47 @@ export default {
this.pos_profile = pos_profile;
this.get_customer_names();
});
evntBus.$on('set_customer', (customer) => {
this.customer = customer;
evntBus.$on("set_customer", (customer) => {
const selected = this.processedCustomers.find(c => c.customer_id === customer);
if (selected) {
this.selectedCustomer = selected.unique_key;
}
});
evntBus.$on('add_customer_to_list', (customer) => {
evntBus.$on("add_customer_to_list", (customer) => {
this.customers.push(customer);
});
evntBus.$on('set_customer_readonly', (value) => {
evntBus.$on("set_customer_readonly", (value) => {
this.readonly = value;
});
evntBus.$on('set_customer_info_to_edit', (data) => {
evntBus.$on("set_customer_info_to_edit", (data) => {
this.customer_info = data;
});
evntBus.$on('fetch_customer_details', () => {
evntBus.$on("fetch_customer_details", () => {
this.get_customer_names();
});
evntBus.$on("customer_updated", () => {
this.$nextTick(() => {
this.selectedCustomer = ""; // Reset setelah update data customer
});
});
});
},

watch: {
customer() {
evntBus.$emit('update_customer', this.customer);
selectedCustomer(newVal) {
if (!newVal) return;

const selectedCustomerObj = this.processedCustomers.find(
(c) => c.unique_key === newVal
);

if (selectedCustomerObj) {
this.customer = selectedCustomerObj.customer_name;
evntBus.$emit("update_customer", this.customer);
this.selectedCustomer = ""; // Reset otomatis setelah update event
} else {
this.selectedCustomer = ""; // Reset jika tidak ditemukan
}
},
},
};
Expand Down
Loading