chore: apply ESLint auto-fix across entire backend
Build and Push Multi-Platform Images / build-and-push (push) Successful in 41s
Build and Push Multi-Platform Images / build-and-push (push) Successful in 41s
Reformats code style (line breaks, indentation, type annotations) without changing logic. Also includes minor feature additions bundled in the same lint run (stats service, user-settings groups, agrarmonitor polling improvements). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,11 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
constructor(
|
||||
private readonly agrarmonitorService: AgrarmonitorService,
|
||||
private readonly paperlessService: PaperlessService,
|
||||
@InjectRepository(Setting) private readonly settingRepo: Repository<Setting>,
|
||||
@InjectRepository(Setting)
|
||||
private readonly settingRepo: Repository<Setting>,
|
||||
@InjectRepository(Client) private readonly clientRepo: Repository<Client>,
|
||||
@InjectRepository(CorrespondentSetting) private readonly corrSettingRepo: Repository<CorrespondentSetting>,
|
||||
@InjectRepository(CorrespondentSetting)
|
||||
private readonly corrSettingRepo: Repository<CorrespondentSetting>,
|
||||
) {}
|
||||
|
||||
async onModuleInit() {
|
||||
@@ -59,23 +61,34 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
@Cron(process.env['AGRARMONITOR_POLLING_CRON'] || '0 */30 * * * *')
|
||||
async scheduledPolling() {
|
||||
if (!process.env['AGRARMONITOR_POLLING_CRON']) return;
|
||||
this.runPolling().catch((err) => this.logger.error('Cron-Polling-Fehler:', err));
|
||||
this.runPolling().catch((err) =>
|
||||
this.logger.error('Cron-Polling-Fehler:', err),
|
||||
);
|
||||
}
|
||||
|
||||
@Cron(process.env['AGRARMONITOR_UPLOAD_CHECK_CRON'] || '0 * * * * *')
|
||||
async scheduledUploadCheck() {
|
||||
if (!process.env['AGRARMONITOR_UPLOAD_CHECK_CRON']) return;
|
||||
this.processVerarbeiteteDocuments().catch((err) => this.logger.error('Cron-Upload-Check-Fehler:', err));
|
||||
this.processVerarbeiteteDocuments().catch((err) =>
|
||||
this.logger.error('Cron-Upload-Check-Fehler:', err),
|
||||
);
|
||||
}
|
||||
|
||||
async getPollingConfig(): Promise<{ tagFertig: string; tagVerbucht: string; tagHochgeladen: string; linkField: string; tagManuell: string }> {
|
||||
const [fertig, verbucht, hochgeladen, linkField, manuell] = await Promise.all([
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_fertig' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_verbucht' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_hochgeladen' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_link_field' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_manuell' }),
|
||||
]);
|
||||
async getPollingConfig(): Promise<{
|
||||
tagFertig: string;
|
||||
tagVerbucht: string;
|
||||
tagHochgeladen: string;
|
||||
linkField: string;
|
||||
tagManuell: string;
|
||||
}> {
|
||||
const [fertig, verbucht, hochgeladen, linkField, manuell] =
|
||||
await Promise.all([
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_fertig' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_verbucht' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_hochgeladen' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_link_field' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_manuell' }),
|
||||
]);
|
||||
return {
|
||||
tagFertig: fertig?.Wert ?? '4',
|
||||
tagVerbucht: verbucht?.Wert ?? '9',
|
||||
@@ -91,13 +104,34 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
tagHochgeladen: string,
|
||||
linkField: string,
|
||||
tagManuell: string,
|
||||
): Promise<{ tagFertig: string; tagVerbucht: string; tagHochgeladen: string; linkField: string; tagManuell: string }> {
|
||||
): Promise<{
|
||||
tagFertig: string;
|
||||
tagVerbucht: string;
|
||||
tagHochgeladen: string;
|
||||
linkField: string;
|
||||
tagManuell: string;
|
||||
}> {
|
||||
await Promise.all([
|
||||
this.settingRepo.update({ Tag: 'agrarmonitor_tag_fertig' }, { Wert: tagFertig }),
|
||||
this.settingRepo.update({ Tag: 'agrarmonitor_tag_verbucht' }, { Wert: tagVerbucht }),
|
||||
this.settingRepo.update({ Tag: 'agrarmonitor_tag_hochgeladen' }, { Wert: tagHochgeladen }),
|
||||
this.settingRepo.update({ Tag: 'agrarmonitor_link_field' }, { Wert: linkField }),
|
||||
this.settingRepo.update({ Tag: 'agrarmonitor_tag_manuell' }, { Wert: tagManuell }),
|
||||
this.settingRepo.update(
|
||||
{ Tag: 'agrarmonitor_tag_fertig' },
|
||||
{ Wert: tagFertig },
|
||||
),
|
||||
this.settingRepo.update(
|
||||
{ Tag: 'agrarmonitor_tag_verbucht' },
|
||||
{ Wert: tagVerbucht },
|
||||
),
|
||||
this.settingRepo.update(
|
||||
{ Tag: 'agrarmonitor_tag_hochgeladen' },
|
||||
{ Wert: tagHochgeladen },
|
||||
),
|
||||
this.settingRepo.update(
|
||||
{ Tag: 'agrarmonitor_link_field' },
|
||||
{ Wert: linkField },
|
||||
),
|
||||
this.settingRepo.update(
|
||||
{ Tag: 'agrarmonitor_tag_manuell' },
|
||||
{ Wert: tagManuell },
|
||||
),
|
||||
]);
|
||||
return { tagFertig, tagVerbucht, tagHochgeladen, linkField, tagManuell };
|
||||
}
|
||||
@@ -105,11 +139,21 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
async runPolling(): Promise<PollingResult> {
|
||||
if (this.pollingRunning) {
|
||||
this.logger.warn('Polling läuft bereits, überspringe');
|
||||
return { processed: 0, updated: 0, skipped: 0, errors: ['Polling bereits aktiv'] };
|
||||
return {
|
||||
processed: 0,
|
||||
updated: 0,
|
||||
skipped: 0,
|
||||
errors: ['Polling bereits aktiv'],
|
||||
};
|
||||
}
|
||||
this.pollingRunning = true;
|
||||
|
||||
const result: PollingResult = { processed: 0, updated: 0, skipped: 0, errors: [] };
|
||||
const result: PollingResult = {
|
||||
processed: 0,
|
||||
updated: 0,
|
||||
skipped: 0,
|
||||
errors: [],
|
||||
};
|
||||
this.logger.log('Starte Agrarmonitor-Polling');
|
||||
|
||||
try {
|
||||
@@ -126,7 +170,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
return { ...result, errors: [msg] };
|
||||
}
|
||||
|
||||
let amClient: Awaited<ReturnType<typeof this.agrarmonitorService.getClient>>;
|
||||
let amClient: Awaited<
|
||||
ReturnType<typeof this.agrarmonitorService.getClient>
|
||||
>;
|
||||
try {
|
||||
amClient = await this.agrarmonitorService.getClient();
|
||||
} catch (err: unknown) {
|
||||
@@ -150,7 +196,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
try {
|
||||
await this.getOrCreateCorrespondent(customer, Number(customer.id));
|
||||
} catch (err: unknown) {
|
||||
this.logger.warn(`Korrespondenten-Sync fehlgeschlagen: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.warn(
|
||||
`Korrespondenten-Sync fehlgeschlagen: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +210,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
});
|
||||
const docs: any[] = docsResponse?.results ?? [];
|
||||
if ((docsResponse?.count ?? 0) > DOCS_PAGE_SIZE) {
|
||||
this.logger.warn(`Mehr als ${DOCS_PAGE_SIZE} Dokumente bereit — nur erste ${DOCS_PAGE_SIZE} werden verarbeitet`);
|
||||
this.logger.warn(
|
||||
`Mehr als ${DOCS_PAGE_SIZE} Dokumente bereit — nur erste ${DOCS_PAGE_SIZE} werden verarbeitet`,
|
||||
);
|
||||
}
|
||||
this.logger.log(`${docs.length} Dokumente fertig in Agrarmonitor`);
|
||||
|
||||
@@ -170,20 +220,25 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
result.processed++;
|
||||
|
||||
const interneBelegnummer =
|
||||
((doc.custom_fields as any[]) ?? []).find(
|
||||
(((doc.custom_fields as any[]) ?? []).find(
|
||||
(cf: any) => cf.field === INTERN_BELEGNUMMER_FIELD_ID,
|
||||
)?.value as string ?? '';
|
||||
)?.value as string) ?? '';
|
||||
|
||||
if (!interneBelegnummer) {
|
||||
this.logger.log(`Dokument ${doc.id as number} hat keine interne Belegnummer`);
|
||||
this.logger.log(
|
||||
`Dokument ${doc.id as number} hat keine interne Belegnummer`,
|
||||
);
|
||||
result.skipped++;
|
||||
await this.delay(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
let amResults: Awaited<ReturnType<typeof amClient.eingangsrechnungenLivesearch>>;
|
||||
let amResults: Awaited<
|
||||
ReturnType<typeof amClient.eingangsrechnungenLivesearch>
|
||||
>;
|
||||
try {
|
||||
amResults = await amClient.eingangsrechnungenLivesearch(interneBelegnummer);
|
||||
amResults =
|
||||
await amClient.eingangsrechnungenLivesearch(interneBelegnummer);
|
||||
} catch (err: unknown) {
|
||||
const status = (err as any)?.response?.status;
|
||||
if (status === 401 || status === 403) {
|
||||
@@ -194,14 +249,18 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
break;
|
||||
}
|
||||
const msg = `${interneBelegnummer}: Livesearch-Fehler`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
await this.delay(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amResults.length === 0) {
|
||||
this.logger.log(`${interneBelegnummer} nicht in Agrarmonitor gefunden`);
|
||||
this.logger.log(
|
||||
`${interneBelegnummer} nicht in Agrarmonitor gefunden`,
|
||||
);
|
||||
result.skipped++;
|
||||
await this.delay(500);
|
||||
continue;
|
||||
@@ -219,9 +278,14 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
|
||||
if (!amDoc.interneBelegNummer && interneBelegnummer) {
|
||||
try {
|
||||
await amClient.setLieferscheinNummer(amDoc.eingangId, interneBelegnummer);
|
||||
await amClient.setLieferscheinNummer(
|
||||
amDoc.eingangId,
|
||||
interneBelegnummer,
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
this.logger.warn(`${interneBelegnummer}: Lieferscheinnummer setzen fehlgeschlagen: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.warn(
|
||||
`${interneBelegnummer}: Lieferscheinnummer setzen fehlgeschlagen: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,17 +297,24 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
const eingangsdatum = new Date(eingangsdatumField.value as string);
|
||||
if (!isNaN(eingangsdatum.getTime())) {
|
||||
await amClient.setEingangsdatum(amDoc.eingangId, eingangsdatum);
|
||||
this.logger.log(`Eingangsdatum für ${interneBelegnummer} gesetzt`);
|
||||
this.logger.log(
|
||||
`Eingangsdatum für ${interneBelegnummer} gesetzt`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (amDoc.buchungsDatum) {
|
||||
try {
|
||||
let correspondentId: number | undefined;
|
||||
const customer = customers.find((c) => Number(c.id) === amDoc.kundenId);
|
||||
const customer = customers.find(
|
||||
(c) => Number(c.id) === amDoc.kundenId,
|
||||
);
|
||||
if (customer) {
|
||||
const corr = await this.getOrCreateCorrespondent(customer, amDoc.kundenId);
|
||||
const corr = await this.getOrCreateCorrespondent(
|
||||
customer,
|
||||
amDoc.kundenId,
|
||||
);
|
||||
if (corr) correspondentId = corr.id as number;
|
||||
}
|
||||
|
||||
@@ -254,28 +325,40 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
if (matchedClient) ownerId = matchedClient.PaperlessUserId;
|
||||
|
||||
const currentTags: number[] = (doc.tags as number[]) ?? [];
|
||||
const newTags = [...new Set(currentTags.filter((t) => t !== tagFertigId).concat([tagVerbuchtId]))];
|
||||
const newTags = [
|
||||
...new Set(
|
||||
currentTags
|
||||
.filter((t) => t !== tagFertigId)
|
||||
.concat([tagVerbuchtId]),
|
||||
),
|
||||
];
|
||||
|
||||
const updateData: Record<string, any> = { tags: newTags };
|
||||
if (correspondentId !== undefined) updateData.correspondent = correspondentId;
|
||||
if (correspondentId !== undefined)
|
||||
updateData.correspondent = correspondentId;
|
||||
if (ownerId !== undefined) updateData.owner = ownerId;
|
||||
|
||||
await this.paperlessService.updateDocument(doc.id as number, updateData);
|
||||
await this.paperlessService.updateDocument(
|
||||
doc.id as number,
|
||||
updateData,
|
||||
);
|
||||
this.logger.log(`Beleg ${interneBelegnummer} gebucht`);
|
||||
result.updated++;
|
||||
} catch (err: unknown) {
|
||||
const msg = `${interneBelegnummer}: Update-Fehler`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.delay(500);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Polling abgeschlossen: ${result.processed} verarbeitet, ${result.updated} aktualisiert, ` +
|
||||
`${result.skipped} übersprungen, ${result.errors.length} Fehler`,
|
||||
`${result.skipped} übersprungen, ${result.errors.length} Fehler`,
|
||||
);
|
||||
} finally {
|
||||
this.pollingRunning = false;
|
||||
@@ -287,15 +370,30 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
async processVerarbeiteteDocuments(): Promise<PollingResult> {
|
||||
if (this.uploadCheckRunning) {
|
||||
this.logger.warn('Upload-Check läuft bereits, überspringe');
|
||||
return { processed: 0, updated: 0, skipped: 0, errors: ['Upload-Check bereits aktiv'] };
|
||||
return {
|
||||
processed: 0,
|
||||
updated: 0,
|
||||
skipped: 0,
|
||||
errors: ['Upload-Check bereits aktiv'],
|
||||
};
|
||||
}
|
||||
this.uploadCheckRunning = true;
|
||||
|
||||
const result: PollingResult = { processed: 0, updated: 0, skipped: 0, errors: [] };
|
||||
const result: PollingResult = {
|
||||
processed: 0,
|
||||
updated: 0,
|
||||
skipped: 0,
|
||||
errors: [],
|
||||
};
|
||||
this.logger.log('Starte Upload-Check');
|
||||
|
||||
try {
|
||||
const [hochgeladenSetting, fertigSetting, linkFieldSetting, manuellSetting] = await Promise.all([
|
||||
const [
|
||||
hochgeladenSetting,
|
||||
fertigSetting,
|
||||
linkFieldSetting,
|
||||
manuellSetting,
|
||||
] = await Promise.all([
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_hochgeladen' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_tag_fertig' }),
|
||||
this.settingRepo.findOneBy({ Tag: 'agrarmonitor_link_field' }),
|
||||
@@ -308,11 +406,15 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
const tagManuellId = parseInt(manuellSetting?.Wert ?? '', 10);
|
||||
|
||||
if (isNaN(tagHochgeladenId)) {
|
||||
this.logger.warn('Tag "hochgeladen" nicht konfiguriert — Upload-Check übersprungen');
|
||||
this.logger.warn(
|
||||
'Tag "hochgeladen" nicht konfiguriert — Upload-Check übersprungen',
|
||||
);
|
||||
return { ...result, errors: ['Tag "hochgeladen" nicht konfiguriert'] };
|
||||
}
|
||||
|
||||
let amClient: Awaited<ReturnType<typeof this.agrarmonitorService.getClient>>;
|
||||
let amClient: Awaited<
|
||||
ReturnType<typeof this.agrarmonitorService.getClient>
|
||||
>;
|
||||
try {
|
||||
amClient = await this.agrarmonitorService.getClient();
|
||||
} catch (err: unknown) {
|
||||
@@ -329,20 +431,26 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
});
|
||||
const docs: any[] = docsResponse?.results ?? [];
|
||||
if ((docsResponse?.count ?? 0) > DOCS_PAGE_SIZE) {
|
||||
this.logger.warn(`Mehr als ${DOCS_PAGE_SIZE} Dokumente hochgeladen — nur erste ${DOCS_PAGE_SIZE} werden geprüft`);
|
||||
this.logger.warn(
|
||||
`Mehr als ${DOCS_PAGE_SIZE} Dokumente hochgeladen — nur erste ${DOCS_PAGE_SIZE} werden geprüft`,
|
||||
);
|
||||
}
|
||||
this.logger.log(`${docs.length} Dokumente laut Paperless im Dateieingang`);
|
||||
this.logger.log(
|
||||
`${docs.length} Dokumente laut Paperless im Dateieingang`,
|
||||
);
|
||||
|
||||
for (const doc of docs) {
|
||||
result.processed++;
|
||||
|
||||
const interneBelegnummer =
|
||||
((doc.custom_fields as any[]) ?? []).find(
|
||||
(((doc.custom_fields as any[]) ?? []).find(
|
||||
(cf: any) => cf.field === INTERN_BELEGNUMMER_FIELD_ID,
|
||||
)?.value as string ?? '';
|
||||
)?.value as string) ?? '';
|
||||
|
||||
if (!interneBelegnummer) {
|
||||
this.logger.log(`Dokument ${doc.id as number} hat keine interne Belegnummer`);
|
||||
this.logger.log(
|
||||
`Dokument ${doc.id as number} hat keine interne Belegnummer`,
|
||||
);
|
||||
result.skipped++;
|
||||
await this.delay(500);
|
||||
continue;
|
||||
@@ -350,7 +458,8 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
|
||||
let vorhanden: boolean;
|
||||
try {
|
||||
vorhanden = await amClient.eingangsrechnungVorhanden(interneBelegnummer);
|
||||
vorhanden =
|
||||
await amClient.eingangsrechnungVorhanden(interneBelegnummer);
|
||||
} catch (err: unknown) {
|
||||
const status = (err as any)?.response?.status;
|
||||
if (status === 401 || status === 403) {
|
||||
@@ -361,7 +470,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
break;
|
||||
}
|
||||
const msg = `${interneBelegnummer}: Vorhanden-Check fehlgeschlagen`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
await this.delay(500);
|
||||
continue;
|
||||
@@ -371,7 +482,10 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
// Prüfen ob Beleg noch im Dateieingang von Agrarmonitor liegt
|
||||
let imDateieingang: boolean;
|
||||
try {
|
||||
imDateieingang = await amClient.eingangsrechnungImDateieingangVorhanden(interneBelegnummer);
|
||||
imDateieingang =
|
||||
await amClient.eingangsrechnungImDateieingangVorhanden(
|
||||
interneBelegnummer,
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
const status = (err as any)?.response?.status;
|
||||
if (status === 401 || status === 403) {
|
||||
@@ -383,7 +497,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
}
|
||||
// Bei Fehler vorsichtig: nicht verschieben
|
||||
const msg = `${interneBelegnummer}: Dateieingang-Check fehlgeschlagen`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
await this.delay(500);
|
||||
continue;
|
||||
@@ -399,9 +515,19 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
// Weder verbucht noch im Dateieingang → Tags "Manuell bearbeiten" + "Von AM zurück" setzen
|
||||
if (!isNaN(tagManuellId)) {
|
||||
const currentTags: number[] = (doc.tags as number[]) ?? [];
|
||||
const newTags = [...new Set(currentTags.filter(t => t !== tagHochgeladenId).concat([tagManuellId, 19]))];
|
||||
await this.paperlessService.updateDocument(doc.id as number, { tags: newTags });
|
||||
this.logger.log(`${interneBelegnummer} nicht mehr in Agrarmonitor — als manuell bearbeiten markiert`);
|
||||
const newTags = [
|
||||
...new Set(
|
||||
currentTags
|
||||
.filter((t) => t !== tagHochgeladenId)
|
||||
.concat([tagManuellId, 19]),
|
||||
),
|
||||
];
|
||||
await this.paperlessService.updateDocument(doc.id as number, {
|
||||
tags: newTags,
|
||||
});
|
||||
this.logger.log(
|
||||
`${interneBelegnummer} nicht mehr in Agrarmonitor — als manuell bearbeiten markiert`,
|
||||
);
|
||||
result.updated++;
|
||||
} else {
|
||||
result.skipped++;
|
||||
@@ -410,11 +536,16 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.log(`Dokument ${interneBelegnummer} ist bereits verarbeitet, aktualisiere Paperless`);
|
||||
this.logger.log(
|
||||
`Dokument ${interneBelegnummer} ist bereits verarbeitet, aktualisiere Paperless`,
|
||||
);
|
||||
|
||||
let amResults: Awaited<ReturnType<typeof amClient.eingangsrechnungenLivesearch>>;
|
||||
let amResults: Awaited<
|
||||
ReturnType<typeof amClient.eingangsrechnungenLivesearch>
|
||||
>;
|
||||
try {
|
||||
amResults = await amClient.eingangsrechnungenLivesearch(interneBelegnummer);
|
||||
amResults =
|
||||
await amClient.eingangsrechnungenLivesearch(interneBelegnummer);
|
||||
} catch (err: unknown) {
|
||||
const status = (err as any)?.response?.status;
|
||||
if (status === 401 || status === 403) {
|
||||
@@ -425,14 +556,18 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
break;
|
||||
}
|
||||
const msg = `${interneBelegnummer}: Livesearch-Fehler`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
await this.delay(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amResults.length > 1) {
|
||||
this.logger.log(`Dokument ${interneBelegnummer} ist doppelt vorhanden`);
|
||||
this.logger.log(
|
||||
`Dokument ${interneBelegnummer} ist doppelt vorhanden`,
|
||||
);
|
||||
result.skipped++;
|
||||
await this.delay(500);
|
||||
continue;
|
||||
@@ -443,29 +578,49 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
try {
|
||||
// Kundendaten abrufen
|
||||
const customer = await amClient.getCustomerById(amDoc.kundenId);
|
||||
const lieferantennummer = (customer['lieferantennummer'] as string) ?? '';
|
||||
const lieferantennummer =
|
||||
(customer['lieferantennummer'] as string) ?? '';
|
||||
if (!lieferantennummer) {
|
||||
this.logger.log(`Kunde ${amDoc.kundenId} hat keine Lieferantennummer — Dokument wird übersprungen`);
|
||||
this.logger.log(
|
||||
`Kunde ${amDoc.kundenId} hat keine Lieferantennummer — Dokument wird übersprungen`,
|
||||
);
|
||||
result.skipped++;
|
||||
await this.delay(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Korrespondent ermitteln oder anlegen
|
||||
const corr = await this.getOrCreateCorrespondent(customer, amDoc.kundenId);
|
||||
const corr = await this.getOrCreateCorrespondent(
|
||||
customer,
|
||||
amDoc.kundenId,
|
||||
);
|
||||
|
||||
// Owner aus Client-Tabelle
|
||||
let ownerId: number | undefined;
|
||||
const matchedClient = await this.clientRepo.findOneBy({ AgrarmonitorBetriebId: amDoc.betriebId });
|
||||
const matchedClient = await this.clientRepo.findOneBy({
|
||||
AgrarmonitorBetriebId: amDoc.betriebId,
|
||||
});
|
||||
if (matchedClient) ownerId = matchedClient.PaperlessUserId;
|
||||
|
||||
// Tags: hochgeladen entfernen, fertig hinzufügen
|
||||
const currentTags: number[] = (doc.tags as number[]) ?? [];
|
||||
const newTags = [...new Set(currentTags.filter((t) => t !== tagHochgeladenId).concat([tagFertigId]))];
|
||||
const newTags = [
|
||||
...new Set(
|
||||
currentTags
|
||||
.filter((t) => t !== tagHochgeladenId)
|
||||
.concat([tagFertigId]),
|
||||
),
|
||||
];
|
||||
|
||||
// Custom fields aufbauen: bestehende behalten, extern + link setzen
|
||||
const existingFields: any[] = ((doc.custom_fields as any[]) ?? []).map((f: any) => ({ ...f }));
|
||||
this.setCustomField(existingFields, EXTERN_BELEGNUMMER_FIELD_ID, amDoc.belegNummer);
|
||||
const existingFields: any[] = (
|
||||
(doc.custom_fields as any[]) ?? []
|
||||
).map((f: any) => ({ ...f }));
|
||||
this.setCustomField(
|
||||
existingFields,
|
||||
EXTERN_BELEGNUMMER_FIELD_ID,
|
||||
amDoc.belegNummer,
|
||||
);
|
||||
if (!isNaN(linkFieldId)) {
|
||||
this.setCustomField(
|
||||
existingFields,
|
||||
@@ -475,16 +630,21 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
}
|
||||
|
||||
const updateData: Record<string, any> = {
|
||||
title: (amDoc.dokumentTyp === 0 ? 'ERG ' : 'EGU ') + amDoc.belegNummer,
|
||||
title:
|
||||
(amDoc.dokumentTyp === 0 ? 'ERG ' : 'EGU ') + amDoc.belegNummer,
|
||||
document_type: amDoc.dokumentTyp === 0 ? 1 : 2,
|
||||
tags: newTags,
|
||||
custom_fields: existingFields,
|
||||
};
|
||||
if (amDoc.belegDatum) updateData.created = amDoc.belegDatum.toISOString().slice(0, 10);
|
||||
if (amDoc.belegDatum)
|
||||
updateData.created = amDoc.belegDatum.toISOString().slice(0, 10);
|
||||
if (corr) updateData.correspondent = corr.id as number;
|
||||
if (ownerId !== undefined) updateData.owner = ownerId;
|
||||
|
||||
await this.paperlessService.updateDocument(doc.id as number, updateData);
|
||||
await this.paperlessService.updateDocument(
|
||||
doc.id as number,
|
||||
updateData,
|
||||
);
|
||||
await this.paperlessService.addNote(
|
||||
doc.id as number,
|
||||
`Beleg in Agrarmonitor verarbeitet: ${new Date().toLocaleString('de-DE')}`,
|
||||
@@ -493,7 +653,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
result.updated++;
|
||||
} catch (err: unknown) {
|
||||
const msg = `${interneBelegnummer}: Update-Fehler`;
|
||||
this.logger.error(`${msg}: ${err instanceof Error ? err.message : err}`);
|
||||
this.logger.error(
|
||||
`${msg}: ${err instanceof Error ? err.message : err}`,
|
||||
);
|
||||
result.errors.push(msg);
|
||||
}
|
||||
|
||||
@@ -502,7 +664,7 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
|
||||
this.logger.log(
|
||||
`Upload-Check abgeschlossen: ${result.processed} geprüft, ${result.updated} aktualisiert, ` +
|
||||
`${result.skipped} übersprungen, ${result.errors.length} Fehler`,
|
||||
`${result.skipped} übersprungen, ${result.errors.length} Fehler`,
|
||||
);
|
||||
} finally {
|
||||
this.uploadCheckRunning = false;
|
||||
@@ -521,16 +683,20 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
}
|
||||
|
||||
async syncCorrespondentIds(): Promise<SyncCorrespondentsResult> {
|
||||
let amClient: Awaited<ReturnType<typeof this.agrarmonitorService.getClient>>;
|
||||
let amClient: Awaited<
|
||||
ReturnType<typeof this.agrarmonitorService.getClient>
|
||||
>;
|
||||
try {
|
||||
amClient = await this.agrarmonitorService.getClient();
|
||||
} catch (err: unknown) {
|
||||
throw new Error(`Connector-Fehler: ${err instanceof Error ? err.message : 'unbekannt'}`);
|
||||
throw new Error(
|
||||
`Connector-Fehler: ${err instanceof Error ? err.message : 'unbekannt'}`,
|
||||
);
|
||||
}
|
||||
|
||||
const customers = await amClient.fetchCustomers();
|
||||
const lieferantMap = new Map<string, number>(); // lieferantennummer → AM-ID
|
||||
const kundenMap = new Map<string, number>(); // kundennummer → AM-ID
|
||||
const kundenMap = new Map<string, number>(); // kundennummer → AM-ID
|
||||
for (const c of customers) {
|
||||
const liefNr = String(c['lieferantennummer'] ?? '').trim();
|
||||
if (liefNr) lieferantMap.set(liefNr, Number(c.id));
|
||||
@@ -541,14 +707,17 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
const allCorrespondents: any[] = [];
|
||||
let page = 1;
|
||||
while (true) {
|
||||
const resp = await this.paperlessService.getCorrespondents({ page, page_size: 250 });
|
||||
const resp = await this.paperlessService.getCorrespondents({
|
||||
page,
|
||||
page_size: 250,
|
||||
});
|
||||
allCorrespondents.push(...(resp.results ?? []));
|
||||
if (!resp.next) break;
|
||||
page++;
|
||||
}
|
||||
|
||||
const lieferantRegex = /\((\d+)\)$/; // reine Zahl → Lieferantennummer
|
||||
const kundenRegex = /\(KD(\d+)\)$/; // KD-Prefix → Kundennummer
|
||||
const lieferantRegex = /\((\d+)\)$/; // reine Zahl → Lieferantennummer
|
||||
const kundenRegex = /\(KD(\d+)\)$/; // KD-Prefix → Kundennummer
|
||||
let matched = 0;
|
||||
let unmatched = 0;
|
||||
|
||||
@@ -564,11 +733,19 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
if (liefMatch) amId = lieferantMap.get(liefMatch[1]);
|
||||
}
|
||||
|
||||
if (amId === undefined) { unmatched++; continue; }
|
||||
if (amId === undefined) {
|
||||
unmatched++;
|
||||
continue;
|
||||
}
|
||||
|
||||
let setting = await this.corrSettingRepo.findOneBy({ CorrespondentId: corr.id as number });
|
||||
let setting = await this.corrSettingRepo.findOneBy({
|
||||
CorrespondentId: corr.id as number,
|
||||
});
|
||||
if (!setting) {
|
||||
setting = this.corrSettingRepo.create({ CorrespondentId: corr.id as number, AgrarmonitorId: amId });
|
||||
setting = this.corrSettingRepo.create({
|
||||
CorrespondentId: corr.id as number,
|
||||
AgrarmonitorId: amId,
|
||||
});
|
||||
} else {
|
||||
setting.AgrarmonitorId = amId;
|
||||
}
|
||||
@@ -594,29 +771,47 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
for (const [amId, corrIds] of byAmId) {
|
||||
if (corrIds.length <= 1) continue;
|
||||
|
||||
const corrs = await Promise.all(corrIds.map(id => this.paperlessService.getCorrespondent(id)));
|
||||
const corrs = await Promise.all(
|
||||
corrIds.map((id) => this.paperlessService.getCorrespondent(id)),
|
||||
);
|
||||
const uniqueNames = new Set(corrs.map((c: any) => c.name as string));
|
||||
|
||||
if (uniqueNames.size === 1) {
|
||||
// Gleicher Name — automatisch zusammenführen
|
||||
const withoutDocs = corrs.filter((c: any) => Number(c.document_count) === 0);
|
||||
const withoutDocs = corrs.filter(
|
||||
(c: any) => Number(c.document_count) === 0,
|
||||
);
|
||||
const withDocs = corrs.filter((c: any) => Number(c.document_count) > 0);
|
||||
|
||||
if (withoutDocs.length > 0) {
|
||||
for (const toDelete of withoutDocs) {
|
||||
await this.paperlessService.deleteCorrespondent(toDelete.id as number);
|
||||
await this.corrSettingRepo.delete({ CorrespondentId: toDelete.id as number });
|
||||
await this.paperlessService.deleteCorrespondent(
|
||||
toDelete.id as number,
|
||||
);
|
||||
await this.corrSettingRepo.delete({
|
||||
CorrespondentId: toDelete.id as number,
|
||||
});
|
||||
autoMerged++;
|
||||
this.logger.log(`Duplikat gelöscht (keine Dokumente): ${toDelete.name as string} (ID ${toDelete.id as number})`);
|
||||
this.logger.log(
|
||||
`Duplikat gelöscht (keine Dokumente): ${toDelete.name as string} (ID ${toDelete.id as number})`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Alle haben Dokumente — in den mit den meisten Dokumenten zusammenführen
|
||||
const sorted = [...withDocs].sort((a: any, b: any) => Number(b.document_count) - Number(a.document_count));
|
||||
const keep = sorted[0] as any;
|
||||
const sorted = [...withDocs].sort(
|
||||
(a: any, b: any) =>
|
||||
Number(b.document_count) - Number(a.document_count),
|
||||
);
|
||||
const keep = sorted[0];
|
||||
for (const toMerge of sorted.slice(1)) {
|
||||
await this.mergeCorrespondents(keep.id as number, toMerge.id as number);
|
||||
await this.mergeCorrespondents(
|
||||
keep.id as number,
|
||||
toMerge.id as number,
|
||||
);
|
||||
autoMerged++;
|
||||
this.logger.log(`Duplikat zusammengeführt in ${keep.name as string} (ID ${keep.id as number})`);
|
||||
this.logger.log(
|
||||
`Duplikat zusammengeführt in ${keep.name as string} (ID ${keep.id as number})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -634,12 +829,21 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
|
||||
this.logger.log(
|
||||
`Korrespondenten-Abgleich: ${matched} zugeordnet, ${unmatched} ohne Treffer, ` +
|
||||
`${autoMerged} automatisch zusammengeführt, ${conflicts.length} Konflikte`,
|
||||
`${autoMerged} automatisch zusammengeführt, ${conflicts.length} Konflikte`,
|
||||
);
|
||||
return { total: allCorrespondents.length, matched, unmatched, autoMerged, conflicts };
|
||||
return {
|
||||
total: allCorrespondents.length,
|
||||
matched,
|
||||
unmatched,
|
||||
autoMerged,
|
||||
conflicts,
|
||||
};
|
||||
}
|
||||
|
||||
async mergeCorrespondents(keepId: number, deleteId: number): Promise<{ mergedDocuments: number }> {
|
||||
async mergeCorrespondents(
|
||||
keepId: number,
|
||||
deleteId: number,
|
||||
): Promise<{ mergedDocuments: number }> {
|
||||
let mergedDocuments = 0;
|
||||
let page = 1;
|
||||
while (true) {
|
||||
@@ -651,7 +855,9 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
});
|
||||
const docs: any[] = resp?.results ?? [];
|
||||
for (const doc of docs) {
|
||||
await this.paperlessService.updateDocument(doc.id as number, { correspondent: keepId });
|
||||
await this.paperlessService.updateDocument(doc.id as number, {
|
||||
correspondent: keepId,
|
||||
});
|
||||
mergedDocuments++;
|
||||
}
|
||||
if (!resp?.next) break;
|
||||
@@ -659,14 +865,21 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
}
|
||||
await this.paperlessService.deleteCorrespondent(deleteId);
|
||||
await this.corrSettingRepo.delete({ CorrespondentId: deleteId });
|
||||
this.logger.log(`Korrespondent ${deleteId} → ${keepId} zusammengeführt (${mergedDocuments} Dokumente)`);
|
||||
this.logger.log(
|
||||
`Korrespondent ${deleteId} → ${keepId} zusammengeführt (${mergedDocuments} Dokumente)`,
|
||||
);
|
||||
return { mergedDocuments };
|
||||
}
|
||||
|
||||
private async getOrCreateCorrespondent(customer: Record<string, unknown>, kundenId?: number): Promise<any> {
|
||||
private async getOrCreateCorrespondent(
|
||||
customer: Record<string, unknown>,
|
||||
kundenId?: number,
|
||||
): Promise<any> {
|
||||
// Direkter Lookup über gespeicherte Agrarmonitor-ID
|
||||
if (kundenId !== undefined) {
|
||||
const setting = await this.corrSettingRepo.findOneBy({ AgrarmonitorId: kundenId });
|
||||
const setting = await this.corrSettingRepo.findOneBy({
|
||||
AgrarmonitorId: kundenId,
|
||||
});
|
||||
if (setting) {
|
||||
return { id: setting.CorrespondentId };
|
||||
}
|
||||
@@ -688,9 +901,14 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
|
||||
// Link für künftige Läufe speichern
|
||||
if (corr && kundenId !== undefined) {
|
||||
let setting = await this.corrSettingRepo.findOneBy({ CorrespondentId: corr.id as number });
|
||||
let setting = await this.corrSettingRepo.findOneBy({
|
||||
CorrespondentId: corr.id as number,
|
||||
});
|
||||
if (!setting) {
|
||||
setting = this.corrSettingRepo.create({ CorrespondentId: corr.id as number, AgrarmonitorId: kundenId });
|
||||
setting = this.corrSettingRepo.create({
|
||||
CorrespondentId: corr.id as number,
|
||||
AgrarmonitorId: kundenId,
|
||||
});
|
||||
} else {
|
||||
setting.AgrarmonitorId = kundenId;
|
||||
}
|
||||
@@ -700,11 +918,14 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
return corr;
|
||||
}
|
||||
|
||||
private buildCustomerName(customer: Record<string, unknown>, nummer: string): string {
|
||||
private buildCustomerName(
|
||||
customer: Record<string, unknown>,
|
||||
nummer: string,
|
||||
): string {
|
||||
const firma = (customer['firma'] as string) ?? '';
|
||||
const nachname = (customer['nachname'] as string) ?? '';
|
||||
const vorname = (customer['vorname'] as string) ?? '';
|
||||
const name = firma || (nachname + (vorname ? ', ' + vorname : ''));
|
||||
const name = firma || nachname + (vorname ? ', ' + vorname : '');
|
||||
return `${name} (${nummer})`;
|
||||
}
|
||||
|
||||
@@ -712,7 +933,10 @@ export class AgrarmonitorPollingService implements OnModuleInit {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
private async upsertSetting(tag: string, defaultValue: string): Promise<void> {
|
||||
private async upsertSetting(
|
||||
tag: string,
|
||||
defaultValue: string,
|
||||
): Promise<void> {
|
||||
const existing = await this.settingRepo.findOneBy({ Tag: tag });
|
||||
if (!existing) {
|
||||
await this.settingRepo.save(
|
||||
|
||||
@@ -20,7 +20,9 @@ export class AgrarmonitorController {
|
||||
@Post('register')
|
||||
@HttpCode(200)
|
||||
@RequirePermissions(Permission.MANAGE_SETTINGS)
|
||||
async registerDevice(@Body() body: { pcName: string; agrarmonitorId: string }) {
|
||||
async registerDevice(
|
||||
@Body() body: { pcName: string; agrarmonitorId: string },
|
||||
) {
|
||||
return this.service.registerDevice(body.pcName, body.agrarmonitorId);
|
||||
}
|
||||
|
||||
@@ -32,8 +34,23 @@ export class AgrarmonitorController {
|
||||
|
||||
@Put('polling-config')
|
||||
@RequirePermissions(Permission.MANAGE_SETTINGS)
|
||||
async updatePollingConfig(@Body() body: { tagFertig: string; tagVerbucht: string; tagHochgeladen: string; linkField: string; tagManuell: string }) {
|
||||
return this.pollingService.updatePollingConfig(body.tagFertig, body.tagVerbucht, body.tagHochgeladen, body.linkField, body.tagManuell ?? '');
|
||||
async updatePollingConfig(
|
||||
@Body()
|
||||
body: {
|
||||
tagFertig: string;
|
||||
tagVerbucht: string;
|
||||
tagHochgeladen: string;
|
||||
linkField: string;
|
||||
tagManuell: string;
|
||||
},
|
||||
) {
|
||||
return this.pollingService.updatePollingConfig(
|
||||
body.tagFertig,
|
||||
body.tagVerbucht,
|
||||
body.tagHochgeladen,
|
||||
body.linkField,
|
||||
body.tagManuell ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
@Post('run-polling')
|
||||
@@ -60,7 +77,9 @@ export class AgrarmonitorController {
|
||||
@Post('merge-correspondents')
|
||||
@HttpCode(200)
|
||||
@RequirePermissions(Permission.MANAGE_SETTINGS)
|
||||
async mergeCorrespondents(@Body() body: { keepId: number; deleteId: number }) {
|
||||
async mergeCorrespondents(
|
||||
@Body() body: { keepId: number; deleteId: number },
|
||||
) {
|
||||
return this.pollingService.mergeCorrespondents(body.keepId, body.deleteId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,38 @@ export class AgrarmonitorService {
|
||||
async getClient(): Promise<AgrarmonitorConnectorResult> {
|
||||
if (this.client) return this.client;
|
||||
|
||||
const username = this.configService.get<string>('AGRARMONITOR_USERNAME', '');
|
||||
const password = this.configService.get<string>('AGRARMONITOR_PASSWORD', '');
|
||||
const baseUrl = this.configService.get<string>('AGRARMONITOR_BASE_URL', 'https://admin7.agrarmonitor.de');
|
||||
const apiBaseUrl = this.configService.get<string>('AGRARMONITOR_API_BASE_URL', 'https://api.agrarmonitor.de');
|
||||
const username = this.configService.get<string>(
|
||||
'AGRARMONITOR_USERNAME',
|
||||
'',
|
||||
);
|
||||
const password = this.configService.get<string>(
|
||||
'AGRARMONITOR_PASSWORD',
|
||||
'',
|
||||
);
|
||||
const baseUrl = this.configService.get<string>(
|
||||
'AGRARMONITOR_BASE_URL',
|
||||
'https://admin7.agrarmonitor.de',
|
||||
);
|
||||
const apiBaseUrl = this.configService.get<string>(
|
||||
'AGRARMONITOR_API_BASE_URL',
|
||||
'https://api.agrarmonitor.de',
|
||||
);
|
||||
const apiToken = this.configService.get<string>('AGRARMONITOR_API_TOKEN');
|
||||
const cookiePath = this.configService.get<string>('AGRARMONITOR_COOKIE_PATH', './data/agrarmonitor-cookies.json');
|
||||
const encryptionKey = this.configService.get<string>('AGRARMONITOR_ENCRYPTION_KEY');
|
||||
const cookiePath = this.configService.get<string>(
|
||||
'AGRARMONITOR_COOKIE_PATH',
|
||||
'./data/agrarmonitor-cookies.json',
|
||||
);
|
||||
const encryptionKey = this.configService.get<string>(
|
||||
'AGRARMONITOR_ENCRYPTION_KEY',
|
||||
);
|
||||
|
||||
const encryptor = encryptionKey ? new AesGcmCookieEncryptor(encryptionKey) : undefined;
|
||||
const cookieStore = new FileCookieStore(cookiePath, { encryptor, logger: this.logger });
|
||||
const encryptor = encryptionKey
|
||||
? new AesGcmCookieEncryptor(encryptionKey)
|
||||
: undefined;
|
||||
const cookieStore = new FileCookieStore(cookiePath, {
|
||||
encryptor,
|
||||
logger: this.logger,
|
||||
});
|
||||
|
||||
this.client = await createAgrarmonitorClient({
|
||||
baseUrl,
|
||||
@@ -84,7 +106,10 @@ export class AgrarmonitorService {
|
||||
}
|
||||
}
|
||||
|
||||
async registerDevice(pcName: string, agrarmonitorId: string): Promise<AgrarmonitorRegisterResultDto> {
|
||||
async registerDevice(
|
||||
pcName: string,
|
||||
agrarmonitorId: string,
|
||||
): Promise<AgrarmonitorRegisterResultDto> {
|
||||
const client = await this.getClient();
|
||||
const result = await client.registerDevice({ agrarmonitorId, pcName });
|
||||
return { success: result.success, message: result.message };
|
||||
|
||||
Reference in New Issue
Block a user