eust-conciliation
Version:
70 lines (54 loc) • 2.08 kB
text/typescript
import { Injectable } from '@severo-tech/injection-decorator';
import { combinations } from '@severo-tech/combinatorial-analysis';
// import cache from 'node-cache-decorator';
export interface ICombinationsValue {
id: string;
value: number | string;
}
()
export class CombinationsUtil {
// @cache('CombinationsUtil.byValue', 60 * 60)
public byValue<T extends ICombinationsValue>(list: T[], target: number, resolveIfDirectMatch = false): T[][] {
const innerList = list
.map((el: T): T & { value: number } => ({ ...el, value: +el.value }));
if (resolveIfDirectMatch) {
const directMatches = innerList.filter((el: T): boolean => el.value === target);
if (directMatches.length) {
return directMatches.map((el: T): T[] => [el]);
}
}
return combinations.byValue(innerList, target);
// const sortedList = innerList.sort((a: T, b: T): number => +b.value - +a.value);
// const combinations = this.findCombination([], sortedList, target);
// return combinations.filter((el: T[]): boolean => el.length > 0);
}
private findCombination<T extends { value: number }>(current: T[], remaining: T[], remainingValue: number): T[][] {
if (remainingValue === 0) {
return [current];
}
if (remainingValue < 0) {
return [];
}
const innerRemaining = remaining.filter((el: T): boolean => el.value <= remainingValue);
if (innerRemaining.length === 0) {
return [];
}
const sumOfRemaining = innerRemaining.reduce((total: number, el: T): number => +(total + el.value).toFixed(2), 0);
if (sumOfRemaining < remainingValue) {
return [];
}
const invoice = innerRemaining[0];
const invoiceValue = invoice.value;
const includeNote = this.findCombination(
[...current, invoice],
innerRemaining.slice(1),
+(remainingValue - invoiceValue).toFixed(2),
);
const excludeNote = this.findCombination(
current,
innerRemaining.slice(1),
remainingValue,
);
return [...includeNote, ...excludeNote];
}
}