rewe-ebon-parser
Version:
A parser for REWE eBons
244 lines • 15 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseEBon = parseEBon;
var pdf_parse_1 = __importDefault(require("pdf-parse"));
/**
* Create a Receipt object from a REWE eBon PDF file.
* @param dataBuffer PDF data
*/
function parseEBon(dataBuffer) {
return __awaiter(this, void 0, void 0, function () {
var data, lines, date, market, marketAddress, cashier, checkout, uid, items, total, given, change, payout, paybackPointsBefore, paybackPoints, paybackRevenue, paybackCardNumber, paybackCoupons, usedREWECredit, newREWECredit, taxDetails, addressMatch, realTotalInCents, totalInCents;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, (0, pdf_parse_1.default)(dataBuffer)];
case 1:
data = _a.sent();
lines = data.text
.replace(/ +/g, ' ')
.split('\n')
.map(function (line) { return line.trim(); })
.filter(function (line) { return line !== ''; });
date = new Date(), market = '?', marketAddress = undefined, cashier = '?', checkout = '?', uid = '?', items = [], total = Number.NaN, given = [], change = Number.NaN, payout = Number.NaN, paybackPointsBefore = Number.NaN, paybackPoints = Number.NaN, paybackRevenue = Number.NaN, paybackCardNumber = '?', paybackCoupons = [], usedREWECredit = Number.NaN, newREWECredit = Number.NaN, taxDetails = {
total: { net: Number.NaN, tax: Number.NaN, gross: Number.NaN }
};
addressMatch = data.text.match(/[\s\*]*([a-zäöüß \d.,-]+?)[\s\*]*(\d{5})\s*([a-zäöüß \d.,-]+)[\s\*]*/im);
if (addressMatch) {
marketAddress = {
street: addressMatch[1].replace(/\s+/g, ' ').replace(/,$/, '').trim(),
zip: addressMatch[2],
city: addressMatch[3].trim(),
};
}
lines.forEach(function (line) {
var itemHit = line.match(/([0-9A-Za-zäöüÄÖÜß &%.!+,\-]*) (-?\d*,\d\d) ([ABC]) ?(\*?)/);
if (itemHit) {
var item = itemHit[1];
var price = parseFloat(itemHit[2].replace(',', '.'));
var category = itemHit[3];
var paybackQualified = !itemHit[4] && price > 0;
items.push({
taxCategory: category,
name: item,
amount: 1,
subTotal: price,
paybackQualified: paybackQualified
});
return;
}
var mengeHit = line.match(/(.*) (.*) x (.*).*/);
if (mengeHit) {
items[items.length - 1] = __assign(__assign({}, items[items.length - 1]), { amount: parseFloat(mengeHit[1].replace(',', '.')), unit: mengeHit[2], pricePerUnit: parseFloat(mengeHit[3].replace(',', '.')) });
return;
}
var totalHit = line.match(/SUMME EUR (-?\d*,\d\d)/);
if (totalHit) {
total = parseFloat(totalHit[1].replace(',', '.'));
return;
}
var gegebenHit = line.match(/Geg\. (.*) EUR ([0-9,]*)/);
if (gegebenHit) {
given.push({
type: gegebenHit[1],
value: parseFloat(gegebenHit[2].replace(',', '.'))
});
return;
}
var returnHit = line.match(/Rückgeld BAR EUR ([0-9,]*)/);
if (returnHit) {
change = parseFloat(returnHit[1].replace(',', '.'));
return;
}
var payoutMatch = line.match(/AUSZAHLUNG EUR ([0-9,]*)/);
if (payoutMatch) {
payout = parseFloat(payoutMatch[1].replace(',', '.'));
return;
}
var timestampHit = line.match(/(\d*)\.(\d*)\.(\d*) (\d*):(\d*) Bon-Nr\.:(.*)/);
if (timestampHit) {
date = new Date(Date.UTC(parseInt(timestampHit[3]), parseInt(timestampHit[2]) - 1, parseInt(timestampHit[1]), parseInt(timestampHit[4]), parseInt(timestampHit[5])));
return;
}
var marktMatch = line.match(/Markt:(.*) Kasse:(.*) Bed\.:(.*)/);
if (marktMatch) {
market = marktMatch[1];
checkout = marktMatch[2];
cashier = marktMatch[3];
return;
}
var uidMatch = line.match(/UID Nr.: (.*)/);
if (uidMatch) {
uid = uidMatch[1];
return;
}
var paybackPointsMatch = line.match(/Sie erhalten (\d*) PAYBACK Punkte? auf|Mit diesem Einkauf gesammelt: (\d*) Punkte?/);
if (paybackPointsMatch) {
var match = paybackPointsMatch.slice(1).find(function (group) { return group != null; });
paybackPoints = parseInt(match);
return;
}
var paybackRevenueMatch = line.match(/einen PAYBACK Umsatz von (.*) EUR!/);
if (paybackRevenueMatch) {
paybackRevenue = parseFloat(paybackRevenueMatch[1].replace(',', '.'));
return;
}
var paybackPointsBeforeMatch = line.match(/Punktestand vor Einkauf: ([0-9.]*)|Punkte vor dem Einkauf: ([0-9.]*)/);
if (paybackPointsBeforeMatch) {
var match = paybackPointsBeforeMatch.slice(1).find(function (group) { return group != null; });
paybackPointsBefore = parseFloat(match.replace('.', ''));
return;
}
var paybackCardNumberMatch = line.match(/PAYBACK Karten-Nr\.: ([0-9#]*)/);
if (paybackCardNumberMatch) {
paybackCardNumber = paybackCardNumberMatch[1];
return;
}
var paybackCouponMatch = line.match(/(.*) ([0-9.]*) Punkte?/);
if (paybackCouponMatch) {
paybackCoupons.push({
name: paybackCouponMatch[1],
points: parseInt(paybackCouponMatch[2].replace('.', ''))
});
return;
}
var taxDetailsMatch = line.match(/([ABC])= ([0-9,]*)% ([0-9,]*) ([0-9,]*) ([0-9,]*)/);
if (taxDetailsMatch) {
taxDetails[taxDetailsMatch[1]] = {
taxPercent: parseFloat(taxDetailsMatch[2].replace(',', '.')),
net: parseFloat(taxDetailsMatch[3].replace(',', '.')),
tax: parseFloat(taxDetailsMatch[4].replace(',', '.')),
gross: parseFloat(taxDetailsMatch[5].replace(',', '.')),
};
return;
}
var totalTaxMatch = line.match(/Gesamtbetrag ([0-9,]*) ([0-9,]*) ([0-9,]*)/);
if (totalTaxMatch) {
taxDetails.total = {
net: parseFloat(totalTaxMatch[1].replace(',', '.')),
tax: parseFloat(totalTaxMatch[2].replace(',', '.')),
gross: parseFloat(totalTaxMatch[3].replace(',', '.')),
};
return;
}
var usedREWECreditMatch = line.match(/Eingesetztes REWE Guthaben: ([0-9,]*) EUR/);
if (usedREWECreditMatch) {
usedREWECredit = parseFloat(usedREWECreditMatch[1].replace(',', '.'));
}
var newREWECreditMatch = line.match(/Neues REWE Guthaben: ([0-9,]*) EUR/);
if (newREWECreditMatch) {
newREWECredit = parseFloat(newREWECreditMatch[1].replace(',', '.'));
}
});
realTotalInCents = items.reduce(function (accumulator, nextItem) { return accumulator + nextItem.subTotal * 100; }, 0);
totalInCents = total * 100;
if (realTotalInCents.toFixed(2) !== totalInCents.toFixed(2)) {
throw new Error("Something went wrong when parsing the eBon: The eBon states a total sum of ".concat(totalInCents, " but the parser only found items worth ").concat(realTotalInCents, "."));
}
return [2 /*return*/, {
date: date,
market: market,
marketAddress: marketAddress,
cashier: cashier,
checkout: checkout,
vatin: uid,
items: items,
total: total,
given: given,
change: change ? change : undefined,
payout: payout ? payout : undefined,
payback: paybackCardNumber ? ({
card: paybackCardNumber,
pointsBefore: paybackPointsBefore,
earnedPoints: paybackPoints,
get basePoints() {
return this.earnedPoints - this.couponPoints;
},
get couponPoints() {
return this.usedCoupons.reduce(function (accumulator, nextCoupon) { return accumulator + nextCoupon.points; }, 0);
},
get qualifiedRevenue() {
if (!Number.isNaN(paybackRevenue))
return paybackRevenue;
return items.filter(function (item) { return item.paybackQualified || item.subTotal < 0; }).reduce(function (prev, next) { return prev + next.subTotal; }, 0);
},
usedCoupons: paybackCoupons,
usedREWECredit: usedREWECredit ? usedREWECredit : undefined,
newREWECredit: !isNaN(newREWECredit) ? newREWECredit : undefined
}) : undefined,
taxDetails: taxDetails
}];
}
});
});
}
//# sourceMappingURL=index.js.map