Properly implement transaction deduplication
Using my superior HUMAN brain Idiot ram stick
This commit is contained in:
@@ -5,7 +5,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { parseTransactionLine, formatISK } from '@/utils/priceUtils';
|
||||
import { parseTransactionLine, formatISK, PastedTransaction } from '@/utils/priceUtils';
|
||||
import { IndTransactionRecordNoId, IndJobStatusOptions } from '@/lib/pbtypes';
|
||||
import { IndJob } from '@/lib/types';
|
||||
import { X } from 'lucide-react';
|
||||
@@ -16,14 +16,9 @@ interface BatchTransactionFormProps {
|
||||
jobs: IndJob[];
|
||||
}
|
||||
|
||||
interface ParsedTransaction extends IndTransactionRecordNoId {
|
||||
assignedJobId?: string;
|
||||
isDuplicate?: boolean;
|
||||
}
|
||||
|
||||
interface TransactionGroup {
|
||||
itemName: string;
|
||||
transactions: ParsedTransaction[];
|
||||
transactions: PastedTransaction[];
|
||||
totalQuantity: number;
|
||||
totalValue: number;
|
||||
}
|
||||
@@ -59,16 +54,16 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
||||
return dateStr.replace('T', ' ');
|
||||
};
|
||||
|
||||
const createTransactionKey = (parsed: ReturnType<typeof parseTransactionLine>): string => {
|
||||
const createTransactionKey = (parsed: PastedTransaction): string => {
|
||||
if (!parsed) return '';
|
||||
const key = [
|
||||
normalizeDate(parsed.date.toISOString()),
|
||||
normalizeDate(parsed.date.toString()),
|
||||
parsed.itemName,
|
||||
parsed.quantity.toString(),
|
||||
parsed.totalAmount.toString(),
|
||||
parsed.totalPrice.toString(),
|
||||
parsed.buyer,
|
||||
parsed.location
|
||||
].join('|');
|
||||
].join('|');
|
||||
return key;
|
||||
};
|
||||
|
||||
@@ -87,33 +82,25 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
||||
const handlePaste = (value: string) => {
|
||||
setPastedData(value);
|
||||
const lines = value.trim().split('\n');
|
||||
const pasteTransactionMap = new Map<string, ParsedTransaction>();
|
||||
const pasteTransactionMap = new Map<string, PastedTransaction>();
|
||||
|
||||
// STEP 1: First combine all identical transactions within the pasted data
|
||||
lines.forEach((line) => {
|
||||
const parsed = parseTransactionLine(line);
|
||||
const parsed: PastedTransaction | null = parseTransactionLine(line);
|
||||
if (parsed) {
|
||||
const transactionKey = createTransactionKey(parsed);
|
||||
const transactionKey: string = createTransactionKey(parsed);
|
||||
|
||||
if (pasteTransactionMap.has(transactionKey)) {
|
||||
// Merge with existing transaction in paste
|
||||
const existing = pasteTransactionMap.get(transactionKey)!;
|
||||
existing.quantity += parsed.quantity;
|
||||
existing.totalPrice += Math.abs(parsed.totalAmount);
|
||||
existing.totalPrice += Math.abs(parsed.totalPrice);
|
||||
const newKey = createTransactionKey(existing);
|
||||
pasteTransactionMap.set(newKey, existing);
|
||||
pasteTransactionMap.delete(transactionKey); // Remove old key
|
||||
} else {
|
||||
// Add new transaction
|
||||
const newTransaction: ParsedTransaction = {
|
||||
date: parsed.date.toISOString(),
|
||||
quantity: parsed.quantity,
|
||||
itemName: parsed.itemName,
|
||||
unitPrice: parsed.unitPrice,
|
||||
totalPrice: Math.abs(parsed.totalAmount),
|
||||
buyer: parsed.buyer,
|
||||
location: parsed.location,
|
||||
corporation: parsed.corporation,
|
||||
wallet: parsed.wallet
|
||||
};
|
||||
pasteTransactionMap.set(transactionKey, newTransaction);
|
||||
pasteTransactionMap.set(transactionKey, parsed);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -124,6 +111,7 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
||||
const matchingJobId = findMatchingJob(transaction.itemName);
|
||||
if (matchingJobId) {
|
||||
relevantJobIds.add(matchingJobId);
|
||||
transaction.assignedJobId = matchingJobId;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -143,11 +131,11 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
||||
pasteTransactionMap.forEach((transaction, key) => {
|
||||
const isDuplicate = existingTransactionKeys.has(key);
|
||||
transaction.isDuplicate = isDuplicate;
|
||||
|
||||
|
||||
if (isDuplicate) {
|
||||
duplicates++;
|
||||
transaction.assignedJobId = undefined;
|
||||
} else {
|
||||
} else if (!!transaction.assignedJobId) {
|
||||
transaction.assignedJobId = findMatchingJob(transaction.itemName);
|
||||
}
|
||||
});
|
||||
@@ -344,4 +332,4 @@ const BatchTransactionForm: React.FC<BatchTransactionFormProps> = ({ onClose, on
|
||||
);
|
||||
};
|
||||
|
||||
export default BatchTransactionForm;
|
||||
export default BatchTransactionForm;
|
@@ -1,3 +1,4 @@
|
||||
import { IndTransactionRecordNoId } from "@/lib/pbtypes";
|
||||
|
||||
export const parseISKAmount = (iskString: string): number => {
|
||||
// Remove "ISK" and any extra whitespace
|
||||
@@ -26,17 +27,12 @@ export const formatISK = (amount: number): string => {
|
||||
return `${sign}${formatted} ISK`;
|
||||
};
|
||||
|
||||
export const parseTransactionLine = (line: string): {
|
||||
date: Date;
|
||||
quantity: number;
|
||||
itemName: string;
|
||||
unitPrice: number;
|
||||
totalAmount: number;
|
||||
buyer?: string;
|
||||
location?: string;
|
||||
corporation?: string;
|
||||
wallet?: string;
|
||||
} | null => {
|
||||
export type PastedTransaction = IndTransactionRecordNoId & {
|
||||
assignedJobId?: string;
|
||||
isDuplicate?: boolean;
|
||||
}
|
||||
|
||||
export const parseTransactionLine = (line: string): PastedTransaction | null => {
|
||||
try {
|
||||
const parts = line.split('\t');
|
||||
if (parts.length < 6) return null;
|
||||
@@ -60,14 +56,14 @@ export const parseTransactionLine = (line: string): {
|
||||
|
||||
// Parse prices
|
||||
const unitPrice = parseISKAmount(unitPriceStr);
|
||||
const totalAmount = parseISKAmount(totalAmountStr);
|
||||
const totalPrice = parseISKAmount(totalAmountStr);
|
||||
|
||||
return {
|
||||
date,
|
||||
date: date.toISOString(),
|
||||
quantity,
|
||||
itemName,
|
||||
unitPrice,
|
||||
totalAmount,
|
||||
totalPrice,
|
||||
buyer,
|
||||
location,
|
||||
corporation,
|
||||
|
Reference in New Issue
Block a user