mirror of
https://github.com/frappe/books.git
synced 2026-08-24 02:24:17 -05:00
localization: add Arabic translation for quick quantity shortcut and update relevant components to emit selected row events
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
@click="isExapanded = !isExapanded"
|
||||
/>
|
||||
|
||||
<div class="relative">
|
||||
<div class="relative" @click="emitSelectedRow">
|
||||
<Link
|
||||
class="pt-2"
|
||||
:df="{
|
||||
@@ -27,7 +27,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<div class="flex items-center" @click="emitSelectedRow">
|
||||
<Int
|
||||
:df="{
|
||||
fieldname: 'quantity',
|
||||
@@ -101,7 +101,7 @@
|
||||
<div></div>
|
||||
|
||||
<template v-if="isExapanded">
|
||||
<div class="px-4 pt-6 col-span-1">
|
||||
<div class="px-4 pt-6 col-span-1" @click="emitSelectedRow">
|
||||
<Int
|
||||
v-if="isUOMConversionEnabled"
|
||||
:df="{
|
||||
@@ -287,7 +287,7 @@ export default defineComponent({
|
||||
props: {
|
||||
row: { type: SalesInvoiceItem, required: true },
|
||||
},
|
||||
emits: ['runSinvFormulas', 'applyPricingRule'],
|
||||
emits: ['runSinvFormulas', 'applyPricingRule', 'selectedRow'],
|
||||
setup() {
|
||||
return {
|
||||
isDiscountingEnabled: inject('isDiscountingEnabled') as boolean,
|
||||
@@ -344,6 +344,9 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
methods: {
|
||||
emitSelectedRow() {
|
||||
this.$emit('selectedRow', this.row);
|
||||
},
|
||||
adjustQuantity(change: number) {
|
||||
let currentQuantity = this.row.quantity ?? 1;
|
||||
let newQuantity = currentQuantity + change;
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
:row="(row as SalesInvoiceItem)"
|
||||
@run-sinv-formulas="runSinvFormulas"
|
||||
@apply-pricing-rule="$emit('applyPricingRule')"
|
||||
@selected-row="selectedItemRow"
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
@@ -94,7 +95,7 @@ export default defineComponent({
|
||||
isExapanded: false,
|
||||
};
|
||||
},
|
||||
emits: ['applyPricingRule'],
|
||||
emits: ['applyPricingRule', 'selectedRow'],
|
||||
computed: {
|
||||
ratio() {
|
||||
return [0.1, 0.9, 0.8, 0.8, 0.8, 0.8, 0.2];
|
||||
@@ -158,6 +159,9 @@ export default defineComponent({
|
||||
async runSinvFormulas() {
|
||||
await this.sinvDoc.runFormulas();
|
||||
},
|
||||
selectedItemRow(row: SalesInvoiceItem) {
|
||||
this.$emit('selectedRow', row);
|
||||
},
|
||||
isNumeric,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -216,6 +216,10 @@ export default defineComponent({
|
||||
shortcut: [ShortcutKey.shift, 'P'],
|
||||
description: t`Set Price List`,
|
||||
},
|
||||
{
|
||||
shortcut: ['Q', '0-9'],
|
||||
description: t`Hold Q and type digits to set selected item quantity`,
|
||||
},
|
||||
{
|
||||
shortcut: [ShortcutKey.pmod, ShortcutKey.shift, 'H'],
|
||||
description: t`Open Saved or Submitted Invoice List.`,
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
|
||||
<SelectedItemTable
|
||||
@apply-pricing-rule="emitEvent('applyPricingRule')"
|
||||
@selected-row="(row) => $emit('selectedRow', row)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -503,6 +504,7 @@ export default defineComponent({
|
||||
'setTransferClearanceDate',
|
||||
'saveAndContinue',
|
||||
'handlePaymentAction',
|
||||
'selectedRow',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -499,6 +499,7 @@ export default defineComponent({
|
||||
'selectedReturnInvoice',
|
||||
'setTransferClearanceDate',
|
||||
'saveAndContinue',
|
||||
'selectedRow',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
@@ -524,6 +525,8 @@ export default defineComponent({
|
||||
selectedRow(row: SalesInvoiceItem, field: string) {
|
||||
this.selectedItemRow = row;
|
||||
this.selectedItemField = field;
|
||||
// Bubble up to POS to allow keyboard shortcuts to target this row
|
||||
this.$emit('selectedRow', row);
|
||||
},
|
||||
getItem,
|
||||
},
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
@set-transfer-clearance-date="setTransferClearanceDate"
|
||||
@save-and-continue="handleSaveAndContinue"
|
||||
@handle-payment-action="handlePaymentAction"
|
||||
@selected-row="setQuickQtySelectedRow"
|
||||
/>
|
||||
<ModernPOS
|
||||
v-else
|
||||
@@ -113,6 +114,7 @@
|
||||
@selected-return-invoice="selectedReturnInvoice"
|
||||
@save-and-continue="handleSaveAndContinue"
|
||||
@set-transfer-clearance-date="setTransferClearanceDate"
|
||||
@selected-row="setQuickQtySelectedRow"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -240,6 +242,13 @@ export default defineComponent({
|
||||
itemQtyMap: {} as ItemQtyMap,
|
||||
coupons: {} as AppliedCouponCodes,
|
||||
itemSerialNumbers: {} as ItemSerialNumbers,
|
||||
|
||||
// Quick Quantity via holding 'Q'
|
||||
quickQtyActive: false,
|
||||
quickQtyBuffer: '' as string,
|
||||
quickQtyRow: null as SalesInvoiceItem | null,
|
||||
quickQtyKeyDownHandler: null as ((e: KeyboardEvent) => void) | null,
|
||||
quickQtyKeyUpHandler: null as ((e: KeyboardEvent) => void) | null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -281,6 +290,7 @@ export default defineComponent({
|
||||
this.setSinvDoc();
|
||||
this.setDefaultCustomer();
|
||||
this.setShortcuts();
|
||||
this.addQuickQtyListeners();
|
||||
|
||||
await this.setItemQtyMap();
|
||||
await this.setItems();
|
||||
@@ -288,8 +298,177 @@ export default defineComponent({
|
||||
deactivated() {
|
||||
this.shortcuts?.delete(COMPONENT_NAME);
|
||||
toggleSidebar(true);
|
||||
this.removeQuickQtyListeners();
|
||||
},
|
||||
methods: {
|
||||
setQuickQtySelectedRow(row: SalesInvoiceItem) {
|
||||
this.quickQtyRow = row;
|
||||
},
|
||||
addQuickQtyListeners() {
|
||||
this.quickQtyKeyDownHandler = (e: KeyboardEvent) =>
|
||||
this.onQuickQtyKeyDown(e);
|
||||
this.quickQtyKeyUpHandler = (e: KeyboardEvent) => this.onQuickQtyKeyUp(e);
|
||||
window.addEventListener(
|
||||
'keydown',
|
||||
this.quickQtyKeyDownHandler as EventListener
|
||||
);
|
||||
window.addEventListener(
|
||||
'keyup',
|
||||
this.quickQtyKeyUpHandler as EventListener
|
||||
);
|
||||
},
|
||||
removeQuickQtyListeners() {
|
||||
if (this.quickQtyKeyDownHandler) {
|
||||
window.removeEventListener(
|
||||
'keydown',
|
||||
this.quickQtyKeyDownHandler as EventListener
|
||||
);
|
||||
this.quickQtyKeyDownHandler = null;
|
||||
}
|
||||
if (this.quickQtyKeyUpHandler) {
|
||||
window.removeEventListener(
|
||||
'keyup',
|
||||
this.quickQtyKeyUpHandler as EventListener
|
||||
);
|
||||
this.quickQtyKeyUpHandler = null;
|
||||
}
|
||||
},
|
||||
hasAnyOpenModal(): boolean {
|
||||
return (
|
||||
this.openAlertModal ||
|
||||
this.openPaymentModal ||
|
||||
this.openKeyboardModal ||
|
||||
this.openPriceListModal ||
|
||||
this.openItemEnquiryModal ||
|
||||
this.openCouponCodeModal ||
|
||||
this.openShiftCloseModal ||
|
||||
this.openSavedInvoiceModal ||
|
||||
this.openLoyaltyProgramModal ||
|
||||
this.openAppliedCouponsModal ||
|
||||
this.openReturnSalesInvoiceModal
|
||||
);
|
||||
},
|
||||
onQuickQtyKeyDown(e: KeyboardEvent) {
|
||||
// Ignore if focus is in an input/contentEditable without modifiers
|
||||
const notMods = !(e.altKey || e.metaKey || e.ctrlKey);
|
||||
const target = e.target as HTMLElement | null;
|
||||
if (
|
||||
target &&
|
||||
notMods &&
|
||||
((target instanceof HTMLInputElement && target.type !== 'button') ||
|
||||
target instanceof HTMLTextAreaElement ||
|
||||
target.isContentEditable)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only active on POS page with no modal open
|
||||
if (this.hasAnyOpenModal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.code === 'KeyQ' && !this.quickQtyActive) {
|
||||
this.quickQtyActive = true;
|
||||
this.quickQtyBuffer = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.quickQtyActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
// While holding Q, collect digits; support both main digits and numpad
|
||||
if (/^Digit[0-9]$/.test(e.code)) {
|
||||
this.quickQtyBuffer += e.code.replace('Digit', '');
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (/^Numpad[0-9]$/.test(e.code)) {
|
||||
this.quickQtyBuffer += e.code.replace('Numpad', '');
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.code === 'Backspace') {
|
||||
this.quickQtyBuffer = this.quickQtyBuffer.slice(0, -1);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
},
|
||||
async onQuickQtyKeyUp(e: KeyboardEvent) {
|
||||
if (e.code !== 'KeyQ' || !this.quickQtyActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.quickQtyActive = false;
|
||||
|
||||
const buffer = this.quickQtyBuffer;
|
||||
this.quickQtyBuffer = '';
|
||||
|
||||
if (!buffer || !buffer.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const qty = Number(buffer);
|
||||
if (!Number.isFinite(qty)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine target row: prefer explicitly selected row; else fallback to last non-free item
|
||||
let row: SalesInvoiceItem | null = this.quickQtyRow;
|
||||
if (!row || !(this.sinvDoc.items || []).includes(row)) {
|
||||
const items = (this.sinvDoc.items || []).filter((r) => !r.isFreeItem);
|
||||
row = items.length
|
||||
? (items[items.length - 1] as SalesInvoiceItem)
|
||||
: null;
|
||||
}
|
||||
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate and recalculate similar to keyboard modal quantity change
|
||||
const prevQty = row.quantity ?? 1;
|
||||
|
||||
if (!row.isReturn && qty <= 0) {
|
||||
showToast({
|
||||
type: 'error',
|
||||
message: t`Quantity must be greater than zero.`,
|
||||
duration: 'short',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await row.set('quantity', qty);
|
||||
|
||||
const existingItems =
|
||||
(this.sinvDoc.items || []).filter(
|
||||
(invoiceItem: InvoiceItem) =>
|
||||
invoiceItem.item === row!.item && !invoiceItem.isFreeItem
|
||||
) || [];
|
||||
|
||||
await validateQty(
|
||||
this.sinvDoc as SalesInvoice,
|
||||
row,
|
||||
existingItems as unknown as InvoiceItem[]
|
||||
);
|
||||
} catch (error) {
|
||||
await row.set('quantity', prevQty);
|
||||
showToast({
|
||||
type: 'error',
|
||||
message: t`${error as string}`,
|
||||
duration: 'short',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!row.isFreeItem) {
|
||||
await this.applyPricingRule();
|
||||
await this.sinvDoc.runFormulas();
|
||||
}
|
||||
},
|
||||
async setCustomer(value: string) {
|
||||
if (!value) {
|
||||
this.sinvDoc.party = '';
|
||||
|
||||
+2
-1
@@ -1098,4 +1098,5 @@ Transfer,تحويل,
|
||||
"Qty","الكمية",
|
||||
"Held","معلّقة",
|
||||
"Grid View","عرض الشبكة",
|
||||
"Buy","شراء",
|
||||
"Buy","شراء",
|
||||
"Hold Q and type digits to set selected item quantity","استمر بالضغط على Q ثم اكتب الأرقام لتعيين كمية الصنف المحدد",
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 148 and column 22.
|
Reference in New Issue
Block a user