Skip to content

Commit 7a71573

Browse files
committed
Fixes for stuff that wasn't working
1 parent ae3238c commit 7a71573

11 files changed

+185
-194
lines changed

package-lock.json

+4-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "migros-api-wrapper",
3-
"version": "1.1.17",
3+
"version": "1.1.20",
44
"description": "Making the api of migros more accessible to the public.",
55
"keywords": [
66
"migros",
@@ -49,6 +49,7 @@
4949
},
5050
"dependencies": {
5151
"cheerio": "^1.0.0-rc.12",
52+
"deepmerge": "^4.3.1",
5253
"dotenv": "^16.4.5",
5354
"pino": "^8.6.1",
5455
"pino-pretty": "^9.1.1"

src/api/apiPaths.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
22
const defaultMigrosApiPath = "https://www.migros.ch";
3+
const defaultMigrosAccountApiPath = "https://account.migros.ch";
34
const defaultMigustoApiPath = "https://migusto.migros.ch";
45

56
export const migrosApiPaths = {
@@ -14,6 +15,7 @@ export const migrosApiPaths = {
1415
public: {
1516
v1: defaultMigrosApiPath + "/product-display/public/v1",
1617
v2: defaultMigrosApiPath + "/product-display/public/v2",
18+
v4: defaultMigrosApiPath + "/product-display/public/v4",
1719
},
1820
},
1921
marketablestock: {
@@ -42,6 +44,11 @@ export const migrosApiPaths = {
4244
},
4345
login: "https://login.migros.ch",
4446
cumulus: "https://cumulus.migros.ch",
47+
account: {
48+
purchases: {
49+
receipts: defaultMigrosAccountApiPath + "/ma/api/user/receipt",
50+
},
51+
},
4552
"mobile-app": "https://mobile-app.migros.ch",
4653
"mobile-api-gateway": "https://mobile-api-gateway.shop.migros.ch",
4754
"subito-go": "https://subito-go.migros.ch",

src/api/cumulus/receipts.ts

+53-108
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,21 @@ import { Language } from "../enums/Language";
1010
import {
1111
ICumulusReceiptArticle,
1212
ICumulusReceiptResponse,
13-
ICumulusReceiptsResponse,
14-
ICumulusReceiptsResponseItem,
1513
} from "../interfaces/receipts";
1614
import { Currency } from "../enums/Currency";
1715

18-
const urlExport =
19-
migrosApiPaths["cumulus"] + "/service/avantaReceiptExport/html";
20-
const urlList =
21-
migrosApiPaths["cumulus"] +
22-
"/de/konto/kassenbons/variants/variant-1/content/04/ajaxContent/0.html";
16+
const urlExport = migrosApiPaths["account"].purchases.receipts;
17+
const urlList = migrosApiPaths["account"].purchases.receipts;
2318

2419
export interface ICumulusReceiptOptions extends Record<string, any> {
25-
receiptId: string;
20+
transactionId: string;
2621
fallbackLanguage?: Language;
2722
}
2823

2924
const defaultCumulusReceiptOptions: ICumulusReceiptOptions = {
30-
receiptId: "",
25+
transactionId: "",
3126
fallbackLanguage: Language.DE,
27+
type: "HTML",
3228
};
3329

3430
async function getCumulusReceiptRequest(
@@ -38,7 +34,13 @@ async function getCumulusReceiptRequest(
3834
htmlOnly: boolean,
3935
): Promise<ICumulusReceiptResponse | string> {
4036
const headers = {
41-
accept: "text/html, */*; q=0.01",
37+
accept: "application/json, text/plain, */*",
38+
"accept-language": "en-US,en;q=0.5",
39+
"sec-fetch-dest": "empty",
40+
"sec-fetch-mode": "cors",
41+
"sec-fetch-site": "same-origin",
42+
"X-CSRF-TOKEN": cookies.CSRF || "",
43+
Referer: "https://account.migros.ch/purchases/receipts",
4244
};
4345

4446
const response = await getRequest(url, options, headers, cookies);
@@ -94,7 +96,7 @@ async function getCumulusReceiptRequest(
9496
return {
9597
store: {
9698
cooperative: store[0].trim(),
97-
outlet: store[1].trim(),
99+
outlet: store[1]?.trim(),
98100
},
99101
articles: receiptArticles,
100102
discount: {
@@ -108,50 +110,50 @@ async function getCumulusReceiptRequest(
108110
currency: <Currency>totalCost[1],
109111
},
110112
payment: {
111-
value: parseFloat(payment[0].trim().split(/\s\s+/)[1].trim()),
113+
value: parseFloat(payment[0].trim().split(/\s\s+/)[1]?.trim()),
112114
type: payment[0].trim().split(/\s\s+/)[0].trim(),
113115
return: payment[1]
114-
? parseFloat(payment[1].trim().split(/\s\s+/)[1].trim())
116+
? parseFloat(payment[1].trim().split(/\s\s+/)[1]?.trim())
115117
: 0,
116118
},
117119
eft: eftPayment
118120
? {
119121
booking: {
120-
type: eftPayment[1].trim().split(/\s\s+/)[1].trim(),
121-
card: eftPayment[2].trim(),
122+
type: eftPayment[1]?.trim().split(/\s\s+/)[1]?.trim(),
123+
card: eftPayment[2]?.trim(),
122124
},
123125
date: new Date(
124-
+eftPayment[3].trim().split(/\s\s+/)[0].trim().split(".")[2],
125-
+eftPayment[3].trim().split(/\s\s+/)[0].trim().split(".")[1] - 1,
126-
+eftPayment[3].trim().split(/\s\s+/)[0].trim().split(".")[0],
127-
+eftPayment[3].trim().split(/\s\s+/)[1].trim().split(":")[0],
128-
+eftPayment[3].trim().split(/\s\s+/)[1].trim().split(":")[1],
126+
+eftPayment[3]?.trim().split(/\s\s+/)[0].trim().split(".")[2],
127+
+eftPayment[3]?.trim().split(/\s\s+/)[0].trim().split(".")[1] - 1,
128+
+eftPayment[3]?.trim().split(/\s\s+/)[0].trim().split(".")[0],
129+
+eftPayment[3]?.trim().split(/\s\s+/)[1].trim().split(":")[0],
130+
+eftPayment[3]?.trim().split(/\s\s+/)[1].trim().split(":")[1],
129131
0,
130132
),
131-
total: parseFloat(eftPayment[5].trim().split(/\s\s+/)[1].trim()),
133+
total: parseFloat(eftPayment[5]?.trim().split(/\s\s+/)[1].trim()),
132134
}
133135
: null,
134136
cumulus: {
135-
nr: cumulus[2].trim().split(/\s\s+/)[1],
137+
nr: cumulus[2]?.trim().split(/\s\s+/)[1],
136138
points: {
137-
current: parseFloat(cumulus[3].trim().split(/\s\s+/)[1]),
138-
received: parseFloat(cumulus[4].trim().split(/\s\s+/)[1]),
139+
current: parseFloat(cumulus[3]?.trim().split(/\s\s+/)[1]),
140+
received: parseFloat(cumulus[4]?.trim().split(/\s\s+/)[1]),
139141
},
140142
},
141143
details: {
142-
outlet: footer[2].trim().split(/\s\s+/)[0],
143-
bed: footer[2].trim().split(/\s\s+/)[1],
144-
box: footer[2].trim().split(/\s\s+/)[2],
145-
bon: footer[2].trim().split(/\s\s+/)[3],
144+
outlet: footer[2]?.trim().split(/\s\s+/)[0],
145+
bed: footer[2]?.trim().split(/\s\s+/)[1],
146+
box: footer[2]?.trim().split(/\s\s+/)[2],
147+
bon: footer[2]?.trim().split(/\s\s+/)[3],
146148
date: new Date(
147-
+footer[2].trim().split(/\s\s+/)[4].split(".")[2],
148-
+footer[2].trim().split(/\s\s+/)[4].split(".")[1] - 1,
149-
+footer[2].trim().split(/\s\s+/)[4].split(".")[0],
150-
+footer[2].trim().split(/\s\s+/)[5].split(":")[0],
151-
+footer[2].trim().split(/\s\s+/)[5].split(":")[1],
152-
+footer[2].trim().split(/\s\s+/)[5].split(":")[2],
149+
+footer[2]?.trim().split(/\s\s+/)[4].split(".")[2],
150+
+footer[2]?.trim().split(/\s\s+/)[4].split(".")[1] - 1,
151+
+footer[2]?.trim().split(/\s\s+/)[4].split(".")[0],
152+
+footer[2]?.trim().split(/\s\s+/)[5].split(":")[0],
153+
+footer[2]?.trim().split(/\s\s+/)[5].split(":")[1],
154+
+footer[2]?.trim().split(/\s\s+/)[5].split(":")[2],
153155
),
154-
letter: footer[2].trim().split(/\s\s+/)[6].trim(),
156+
letter: footer[2]?.trim().split(/\s\s+/)[6].trim(),
155157
},
156158
};
157159
}
@@ -166,7 +168,7 @@ export async function getCumulusReceipt(
166168
...cumulusReceiptOptions,
167169
};
168170
return getCumulusReceiptRequest(
169-
urlExport,
171+
urlExport + "/" + cumulusReceiptOptions.receiptId,
170172
cumulusReceiptOptions,
171173
cookies,
172174
htmlOnly,
@@ -189,100 +191,43 @@ function convertDateToCumulusDateString(date: Date): string {
189191
}
190192

191193
export interface ICumulusReceiptsOptions extends Record<string, any> {
192-
from: Date;
193-
to: Date;
194-
p?: number;
194+
dateFrom: Date;
195+
dateTo?: Date;
195196
}
196197

197198
const defaultCumulusReceiptsOptions: ICumulusReceiptsOptions = {
198-
from: new Date(),
199-
to: new Date(),
200-
p: 1,
201-
sort: "dateDsc",
199+
dateFrom: new Date(),
200+
dateTo: new Date(),
202201
};
203202

204203
async function getCumulusReceiptsRequest(
205204
url: string,
206-
options: ICumulusReceiptsOptions | Record<string, any>,
205+
options: ICumulusReceiptsOptions,
207206
cookies: ICumulusCookies,
208-
): Promise<ICumulusReceiptsResponse> {
207+
): Promise<any> {
209208
const headers = {
210-
accept: "text/html, */*; q=0.01",
211-
"accept-language": "en-US,en;q=0.9",
212-
"sec-ch-ua":
213-
'"Chromium";v="106", "Not;A=Brand";v="99", "Google Chrome";v="106.0.5249.119"',
214-
"sec-ch-ua-mobile": "?0",
215-
"sec-ch-ua-platform": '"Windows"',
209+
accept: "application/json, text/plain, */*",
210+
"accept-language": "en-US,en;q=0.5",
216211
"sec-fetch-dest": "empty",
217212
"sec-fetch-mode": "cors",
218213
"sec-fetch-site": "same-origin",
219-
"x-requested-with": "XMLHttpRequest",
214+
"X-CSRF-TOKEN": cookies.CSRF || "",
215+
Referer: "https://account.migros.ch/purchases/receipts",
220216
};
221217

222218
const newOptions = {
223-
period: `${convertDateToCumulusDateString(
224-
options.from,
225-
)}_${convertDateToCumulusDateString(options.to)}`,
226-
p: options.p,
219+
dateFrom: convertDateToCumulusDateString(options.dateFrom),
220+
dateTo: convertDateToCumulusDateString(options.dateTo || new Date()),
227221
};
228222

229-
const tableData: ICumulusReceiptsResponseItem[] = [];
230-
231-
// eslint-disable-next-line no-loops/no-loops,no-constant-condition
232-
while (true) {
233-
const response = await getRequest(url, newOptions, headers, cookies);
234-
if (!response.text) {
235-
break;
236-
}
237-
238-
const $ = cheerio.load(await response.text());
239-
const links = $(
240-
"[data-modal-src^='/service/avantaReceiptExport/html?receiptId=']",
241-
);
242-
243-
links.each((_, el) => {
244-
const rowItems = $(el).parent().parent().children();
245-
const [day, month, year] = $(rowItems[1]).text().trim().split(".");
246-
tableData.push({
247-
date: new Date(+year, +month - 1, +day),
248-
outlet: $(rowItems[2]).text().trim(),
249-
total: {
250-
value: parseFloat(($(rowItems[3])[0].children[1] as any)["data"]),
251-
currency: ($(rowItems[3])[0].children[0] as any)[
252-
"children"
253-
][0].data.trim(),
254-
},
255-
points: {
256-
value: parseFloat(($(rowItems[4])[0].children[0] as any)["data"]),
257-
},
258-
links: {
259-
html:
260-
migrosApiPaths["cumulus"] +
261-
($(rowItems[1])[0].children[1] as any).attribs["data-modal-src"],
262-
pdf:
263-
migrosApiPaths["cumulus"] +
264-
($(rowItems[1])[0].children[1] as any).attribs.href,
265-
},
266-
id: ($(rowItems[1])[0].children[1] as any).attribs.href.match(
267-
new RegExp(/(?<==).*?(?=&|$)/),
268-
)[0],
269-
});
270-
});
271-
272-
if (links.length < 10) {
273-
break;
274-
}
275-
276-
newOptions.p = newOptions.p + 1;
277-
}
278-
279-
return tableData;
223+
const response = await getRequest(url, newOptions, headers, cookies);
224+
return await response.json();
280225
}
281226

282227
export async function getCumulusReceipts(
283228
cumulusReceiptsOptions: ICumulusReceiptsOptions,
284229
cookies: ICumulusCookies,
285-
): Promise<ICumulusReceiptsResponse> {
230+
): Promise<any> {
286231
cumulusReceiptsOptions = {
287232
...defaultCumulusReceiptsOptions,
288233
...cumulusReceiptsOptions,

src/api/interfaces/cookies.ts

+26-11
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,29 @@ export interface ILoginCookies extends ICookies {
1313
["TS012f1684"]: string;
1414
}
1515

16-
export interface ICumulusCookies extends ICookies {
17-
["BIGipServerpool_shared_migros.ch_80"]?: string;
18-
["REALPERSON_SESSION"]?: string;
19-
["cookie-banner-acceptance-state"]?: string;
20-
["mo-fulfilmentOption"]?: string;
21-
["mo-sidebarsState"]?: string;
22-
["mo-lang"]?: string;
23-
["mo-securityContext"]?: string;
24-
["JSESSIONID"]: string;
25-
["INGRESSCOOKIE"]: string;
26-
}
16+
export type ICumulusCookies = ICookies &
17+
(
18+
| {
19+
["BIGipServerpool_shared_migros.ch_80"]?: string;
20+
["REALPERSON_SESSION"]?: string;
21+
["cookie-banner-acceptance-state"]?: string;
22+
["mo-fulfilmentOption"]?: string;
23+
["mo-sidebarsState"]?: string;
24+
["mo-lang"]?: string;
25+
["mo-securityContext"]?: string;
26+
["JSESSIONID"]: string;
27+
["INGRESSCOOKIE"]: string;
28+
}
29+
| {
30+
["BIGipServerpool_shared_migros.ch_80"]?: string;
31+
["REALPERSON_SESSION"]?: string;
32+
["cookie-banner-acceptance-state"]?: string;
33+
["mo-fulfilmentOption"]?: string;
34+
["mo-sidebarsState"]?: string;
35+
["mo-lang"]?: string;
36+
["mo-securityContext"]?: string;
37+
["JSESSIONID"]: string;
38+
["__VCAP_ID__"]: string;
39+
["CSRF"]: string;
40+
}
41+
);

0 commit comments

Comments
 (0)