Merged PR 643: ライセンス引き戻し完了通知 [U-109] の実装
## 概要 [Task3306: ライセンス引き戻し完了通知 [U-109] の実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3306) - ライセンス引き戻し完了のメール送信機能を追加しました。 - テストでメール送信しないようSendGridのメソッドを上書きする処理を追加しました。 ## レビューポイント - テンプレートの適用内容に不自然な点はないか - アカウントのFromとToとCCに関わる部分で認識違いはないか - `orderedAccountId` という引数には注文したアカウント=下位階層のアカウントが入るという理解であっているか等 ## UIの変更 - なし ## 動作確認状況 - npm run testは通過
This commit is contained in:
parent
60bb8f9e20
commit
1bc6618a6d
4
dictation_client/.vscode/settings.json
vendored
4
dictation_client/.vscode/settings.json
vendored
@ -27,8 +27,8 @@
|
|||||||
"debug.javascript.usePreview": false,
|
"debug.javascript.usePreview": false,
|
||||||
"editor.copyWithSyntaxHighlighting": false,
|
"editor.copyWithSyntaxHighlighting": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true,
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.fixAll.stylelint": true
|
"source.fixAll.stylelint": "explicit"
|
||||||
},
|
},
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
|
|||||||
2
dictation_server/.vscode/settings.json
vendored
2
dictation_server/.vscode/settings.json
vendored
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"terminal.integrated.shell.linux": "/bin/bash",
|
"terminal.integrated.shell.linux": "/bin/bash",
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true
|
"source.fixAll.eslint": "explicit"
|
||||||
},
|
},
|
||||||
"eslint.format.enable": false,
|
"eslint.format.enable": false,
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
|
|||||||
@ -5112,6 +5112,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await service.cancelIssue(
|
await service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
tier1Accounts[0].users[0].external_id,
|
tier1Accounts[0].users[0].external_id,
|
||||||
@ -5175,6 +5176,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await service.cancelIssue(
|
await service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
tier2Accounts[0].users[0].external_id,
|
tier2Accounts[0].users[0].external_id,
|
||||||
@ -5212,6 +5214,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
});
|
});
|
||||||
const poNumber = 'CANCEL_TEST';
|
const poNumber = 'CANCEL_TEST';
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await expect(
|
await expect(
|
||||||
service.cancelIssue(
|
service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
@ -5258,6 +5261,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await expect(
|
await expect(
|
||||||
service.cancelIssue(
|
service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
@ -5304,6 +5308,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await expect(
|
await expect(
|
||||||
service.cancelIssue(
|
service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
@ -5351,6 +5356,7 @@ describe('ライセンス発行キャンセル', () => {
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const service = module.get<AccountsService>(AccountsService);
|
const service = module.get<AccountsService>(AccountsService);
|
||||||
|
overrideSendgridService(service, {});
|
||||||
await expect(
|
await expect(
|
||||||
service.cancelIssue(
|
service.cancelIssue(
|
||||||
makeContext('trackingId', 'requestId'),
|
makeContext('trackingId', 'requestId'),
|
||||||
|
|||||||
@ -1419,11 +1419,42 @@ export class AccountsService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 発行キャンセル処理
|
// 発行キャンセル処理
|
||||||
|
const { canceledIssueLicenseOrderId } =
|
||||||
await this.accountRepository.cancelIssue(
|
await this.accountRepository.cancelIssue(
|
||||||
context,
|
context,
|
||||||
orderedAccountId,
|
orderedAccountId,
|
||||||
poNumber,
|
poNumber,
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
|
// 発行キャンセルされ、発行済状態から注文中状態に戻った注文を取得する
|
||||||
|
const order = await this.licensesRepository.getLicenseOrder(
|
||||||
|
context,
|
||||||
|
orderedAccountId,
|
||||||
|
poNumber,
|
||||||
|
canceledIssueLicenseOrderId,
|
||||||
|
);
|
||||||
|
if (order == null) {
|
||||||
|
throw new Error('order not found.');
|
||||||
|
}
|
||||||
|
const { quantity, from_account_id, to_account_id } = order;
|
||||||
|
const customer = await this.getAccountInformation(
|
||||||
|
context,
|
||||||
|
from_account_id,
|
||||||
|
);
|
||||||
|
const dealer = await this.getAccountInformation(context, to_account_id);
|
||||||
|
await this.sendgridService.sendMailWithU109(
|
||||||
|
context,
|
||||||
|
dealer.adminEmails,
|
||||||
|
dealer.companyName,
|
||||||
|
quantity,
|
||||||
|
poNumber,
|
||||||
|
customer.adminEmails,
|
||||||
|
customer.companyName,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||||
|
// メール送信の例外はログだけ出して握りつぶす
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
||||||
switch (e.constructor) {
|
switch (e.constructor) {
|
||||||
@ -2326,7 +2357,7 @@ export class AccountsService {
|
|||||||
const adminEmails = usersInfo.map((x) => {
|
const adminEmails = usersInfo.map((x) => {
|
||||||
const { emailAddress } = getUserNameAndMailAddress(x);
|
const { emailAddress } = getUserNameAndMailAddress(x);
|
||||||
if (emailAddress == null) {
|
if (emailAddress == null) {
|
||||||
throw new Error('dealer admin email-address is not found');
|
throw new Error(`admin email-address is not found. id=${x.id}`);
|
||||||
}
|
}
|
||||||
return emailAddress;
|
return emailAddress;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -34,6 +34,8 @@ export class SendGridService {
|
|||||||
private readonly templateU107Text: string;
|
private readonly templateU107Text: string;
|
||||||
private readonly templateU108Html: string;
|
private readonly templateU108Html: string;
|
||||||
private readonly templateU108Text: string;
|
private readonly templateU108Text: string;
|
||||||
|
private readonly templateU109Html: string;
|
||||||
|
private readonly templateU109Text: string;
|
||||||
|
|
||||||
constructor(private readonly configService: ConfigService) {
|
constructor(private readonly configService: ConfigService) {
|
||||||
this.appDomain = this.configService.getOrThrow<string>('APP_DOMAIN');
|
this.appDomain = this.configService.getOrThrow<string>('APP_DOMAIN');
|
||||||
@ -99,6 +101,15 @@ export class SendGridService {
|
|||||||
path.resolve(__dirname, `../../templates/template_U_108.txt`),
|
path.resolve(__dirname, `../../templates/template_U_108.txt`),
|
||||||
'utf-8',
|
'utf-8',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.templateU109Html = readFileSync(
|
||||||
|
path.resolve(__dirname, `../../templates/template_U_109.html`),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
|
this.templateU109Text = readFileSync(
|
||||||
|
path.resolve(__dirname, `../../templates/template_U_109.txt`),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +419,61 @@ export class SendGridService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* U-109のテンプレートを使用したメールを送信する
|
||||||
|
* @param context context
|
||||||
|
* @param dealerEmails ライセンス発行をキャンセルした上位アカウントの管理者(primary/secondary)のメールアドレス
|
||||||
|
* @param dealerAccountName ライセンス発行をキャンセルした上位アカウントの会社名
|
||||||
|
* @param lisenceCount ライセンス発行をキャンセルした対象の注文の内容(ライセンス数)
|
||||||
|
* @param poNumber ライセンス発行をキャンセルした対象の注文の内容(PO番号)
|
||||||
|
* @param customerMails ライセンス発行をキャンセルされたアカウントの管理者(primary/secondary)のメールアドレス
|
||||||
|
* @param customerAccountName ライセンス発行をキャンセルされたアカウントの会社名
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async sendMailWithU109(
|
||||||
|
context: Context,
|
||||||
|
dealerEmails: string[],
|
||||||
|
dealerAccountName: string,
|
||||||
|
lisenceCount: number,
|
||||||
|
poNumber: string,
|
||||||
|
customerMails: string[],
|
||||||
|
customerAccountName: string,
|
||||||
|
): Promise<void> {
|
||||||
|
this.logger.log(
|
||||||
|
`[IN] [${context.getTrackingId()}] ${this.sendMailWithU109.name}`,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const subject = 'License Returned Notification [U-109]';
|
||||||
|
|
||||||
|
// メールの本文を作成する
|
||||||
|
const html = this.templateU109Html
|
||||||
|
.replaceAll(CUSTOMER_NAME, customerAccountName)
|
||||||
|
.replaceAll(DEALER_NAME, dealerAccountName)
|
||||||
|
.replaceAll(PO_NUMBER, poNumber)
|
||||||
|
.replaceAll(LICENSE_QUANTITY, `${lisenceCount}`);
|
||||||
|
const text = this.templateU109Text
|
||||||
|
.replaceAll(CUSTOMER_NAME, customerAccountName)
|
||||||
|
.replaceAll(DEALER_NAME, dealerAccountName)
|
||||||
|
.replaceAll(PO_NUMBER, poNumber)
|
||||||
|
.replaceAll(LICENSE_QUANTITY, `${lisenceCount}`);
|
||||||
|
|
||||||
|
// メールを送信する
|
||||||
|
this.sendMail(
|
||||||
|
context,
|
||||||
|
dealerEmails,
|
||||||
|
customerMails,
|
||||||
|
this.mailFrom,
|
||||||
|
subject,
|
||||||
|
text,
|
||||||
|
html,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
this.logger.log(
|
||||||
|
`[OUT] [${context.getTrackingId()}] ${this.sendMailWithU109.name}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* U-108のテンプレートを使用したメールを送信する
|
* U-108のテンプレートを使用したメールを送信する
|
||||||
* @param context
|
* @param context
|
||||||
|
|||||||
@ -774,13 +774,14 @@ export class AccountsRepositoryService {
|
|||||||
* 注文元アカウントIDとPOナンバーに紐づくライセンス発行をキャンセルする
|
* 注文元アカウントIDとPOナンバーに紐づくライセンス発行をキャンセルする
|
||||||
* @param orderedAccountId:キャンセルしたい発行の注文元アカウントID
|
* @param orderedAccountId:キャンセルしたい発行の注文元アカウントID
|
||||||
* @param poNumber:POナンバー
|
* @param poNumber:POナンバー
|
||||||
|
* @returns { canceledIssueLicenseOrderId } : キャンセルされたライセンス発行に紐づく注文ID
|
||||||
*/
|
*/
|
||||||
async cancelIssue(
|
async cancelIssue(
|
||||||
context: Context,
|
context: Context,
|
||||||
orderedAccountId: number,
|
orderedAccountId: number,
|
||||||
poNumber: string,
|
poNumber: string,
|
||||||
): Promise<void> {
|
): Promise<{ canceledIssueLicenseOrderId: number }> {
|
||||||
await this.dataSource.transaction(async (entityManager) => {
|
return await this.dataSource.transaction(async (entityManager) => {
|
||||||
const orderRepo = entityManager.getRepository(LicenseOrder);
|
const orderRepo = entityManager.getRepository(LicenseOrder);
|
||||||
|
|
||||||
// キャンセル対象の発行を取得
|
// キャンセル対象の発行を取得
|
||||||
@ -862,6 +863,8 @@ export class AccountsRepositoryService {
|
|||||||
this.isCommentOut,
|
this.isCommentOut,
|
||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return { canceledIssueLicenseOrderId: targetOrder.id };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
dictation_server/src/templates/template_U_109.html
Normal file
52
dictation_server/src/templates/template_U_109.html
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>License Returned Notification [U-109]</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h3><English></h3>
|
||||||
|
<p>Dear $DEALER_NAME$,</p>
|
||||||
|
<p>
|
||||||
|
Please be informed that the licenses issued with the following contents has been returned from your customer and placed back into your License inventory.<br />
|
||||||
|
- Company Name: $CUSTOMER_NAME$<br />
|
||||||
|
- Number of canceled licenses: $LICENSE_QUANTITY$<br />
|
||||||
|
- PO Number: $PO_NUMBER$
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you have received this e-mail in error, please delete this e-mail from your system.<br />
|
||||||
|
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3><Deutsch></h3>
|
||||||
|
<p>Sehr geehrte(r) $DEALER_NAME$,</p>
|
||||||
|
<p>
|
||||||
|
Bitte beachten Sie, dass die ausgestellten Lizenzen mit den folgenden Inhalten von Ihrem Kunden zurückgegeben und wieder in Ihren Lizenzbestand aufgenommen wurden.<br />
|
||||||
|
- Name der Firma: $CUSTOMER_NAME$<br />
|
||||||
|
- Anzahl der gekündigten Lizenzen: $LICENSE_QUANTITY$<br />
|
||||||
|
- Bestellnummer: $PO_NUMBER$
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.<br />
|
||||||
|
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3><Français></h3>
|
||||||
|
<p>Chère/Cher $DEALER_NAME$,</p>
|
||||||
|
<p>
|
||||||
|
Veuillez noter que les licences émises avec le contenu suivant ont été retournées par votre client et replacées dans votre inventaire de licences.<br />
|
||||||
|
- Nom de l'entreprise: $CUSTOMER_NAME$<br />
|
||||||
|
- Nombre de licences annulées: $LICENSE_QUANTITY$<br />
|
||||||
|
- Numéro de bon de commande $PO_NUMBER$
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.<br />
|
||||||
|
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
35
dictation_server/src/templates/template_U_109.txt
Normal file
35
dictation_server/src/templates/template_U_109.txt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<English>
|
||||||
|
|
||||||
|
Dear $DEALER_NAME$,
|
||||||
|
|
||||||
|
Please be informed that the licenses issued with the following contents has been returned from your customer and placed back into your License inventory.
|
||||||
|
- Company Name: $CUSTOMER_NAME$
|
||||||
|
- Number of canceled licenses: $LICENSE_QUANTITY$
|
||||||
|
- PO Number: $PO_NUMBER$
|
||||||
|
|
||||||
|
If you have received this e-mail in error, please delete this e-mail from your system.
|
||||||
|
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.
|
||||||
|
|
||||||
|
<Deutsch>
|
||||||
|
|
||||||
|
Sehr geehrte(r) $DEALER_NAME$,
|
||||||
|
|
||||||
|
Bitte beachten Sie, dass die ausgestellten Lizenzen mit den folgenden Inhalten von Ihrem Kunden zurückgegeben und wieder in Ihren Lizenzbestand aufgenommen wurden.
|
||||||
|
- Name der Firma: $CUSTOMER_NAME$
|
||||||
|
- Anzahl der gekündigten Lizenzen: $LICENSE_QUANTITY$
|
||||||
|
- Bestellnummer: $PO_NUMBER$
|
||||||
|
|
||||||
|
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
|
||||||
|
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.
|
||||||
|
|
||||||
|
<Français>
|
||||||
|
|
||||||
|
Chère/Cher $DEALER_NAME$,
|
||||||
|
|
||||||
|
Veuillez noter que les licences émises avec le contenu suivant ont été retournées par votre client et replacées dans votre inventaire de licences.
|
||||||
|
- Nom de l'entreprise: $CUSTOMER_NAME$
|
||||||
|
- Nombre de licences annulées: $LICENSE_QUANTITY$
|
||||||
|
- Numéro de bon de commande $PO_NUMBER$
|
||||||
|
|
||||||
|
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.
|
||||||
|
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.
|
||||||
Loading…
x
Reference in New Issue
Block a user