| @@ -1,9 +1,15 @@ | |||
| import { eventHnalder } from "@/common/app-template"; | |||
| import { AppID } from "@/common/appids"; | |||
| import { setHeaderButton } from "@/common/header-button"; | |||
| import { KintoneEvent, 値設定 } from "@/common/kintone-event"; | |||
| import { makeRecordData } from "@/common/rest-api-client"; | |||
| import { Message } from "@/exception"; | |||
| import { EmailID, sendEmail } from "@/mypage/メール"; | |||
| import { makeReceipt } from "@/mypage/領収証発行"; | |||
| import { BulkRequest } from "@/rest-api/bulk"; | |||
| import { get定期申込予約 } from "@/rest-api/定期申込予約"; | |||
| import { 入金予定結果, 入金予定結果フィールド名 } from "@/types/入金予定結果"; | |||
| import { 定期申込予約フィールド名 } from "@/types/定期申込予約"; | |||
| import { KintoneRestAPIClient } from "@kintone/rest-api-client"; | |||
| import { format } from "date-fns"; | |||
| import Swal from "sweetalert2"; | |||
| @@ -74,8 +80,7 @@ const setData = (event: any, targets: string[]) => { | |||
| targets.forEach((target) => { | |||
| const value = param.get(target); | |||
| if (value === null) return; | |||
| event.record[target].value = value; | |||
| event.record[target].lookup = true; | |||
| 値設定(event, target, value, true); | |||
| }); | |||
| }; | |||
| (() => { | |||
| @@ -92,7 +97,61 @@ const setData = (event: any, targets: string[]) => { | |||
| } | |||
| }); | |||
| kintone.events.on("app.record.create.show", (event) => { | |||
| const 初回請求金額確定チェック = (record: 入金予定結果) => { | |||
| if (!record.first_payment_entry_record_no.value) { | |||
| throw new Message("初回振り込み関連申込レコード番号が入力されていません"); | |||
| } | |||
| // 申込の初回振り込み情報を入力する | |||
| const F = 定期申込予約フィールド名; | |||
| const 支払予定日 = record.payment_plan_date.value; | |||
| if (!支払予定日) { | |||
| throw new Message("支払予定日が入力されていません"); | |||
| } | |||
| const 支払予定金額 = record.payment_plan_amount.value; | |||
| if (!支払予定金額) { | |||
| throw new Message("支払予定金額が入力されていません"); | |||
| } | |||
| }; | |||
| const 初回請求金額確定 = async (record: 入金予定結果) => { | |||
| 初回請求金額確定チェック(record); | |||
| const 申込 = await get定期申込予約( | |||
| record.first_payment_entry_record_no.value | |||
| ); | |||
| // 申込の初回振り込み情報を入力する | |||
| const F = 定期申込予約フィールド名; | |||
| const 支払予定日 = record.payment_plan_date.value ?? ""; | |||
| const 支払予定金額 = record.payment_plan_amount.value ?? ""; | |||
| const 日割り金額 = Number(支払予定金額) - Number(申込.定期駐車料金.value); | |||
| const 日割り月 = (() => { | |||
| if (日割り金額 === 0) return ""; | |||
| let month = Number(record.target_month.value) - 1; | |||
| if (month === 0) { | |||
| month = 12; | |||
| } | |||
| return String(month); | |||
| })(); | |||
| const request = new BulkRequest(); | |||
| request.update({ | |||
| app: AppID.定期申込予約, | |||
| id: record.first_payment_entry_record_no.value, | |||
| record: makeRecordData({ | |||
| [F.振込期日]: 支払予定日, | |||
| [F.初回振り込み合計額]: 支払予定金額, | |||
| [F.請求対象分_月]: record.target_month.value, | |||
| [F.請求対象分_金額]: 申込.定期駐車料金.value, | |||
| [F.日割り分_金額]: String(日割り金額), | |||
| [F.日割り分_月]: 日割り月, | |||
| }), | |||
| }); | |||
| await request.save(); | |||
| }; | |||
| kintone.events.on(KintoneEvent.追加.レコード追加画面を表示した後, (event) => { | |||
| setData(event, [ | |||
| 入金予定結果フィールド名.車室契約情報レコード番号, | |||
| 入金予定結果フィールド名.初回振り込み関連申込レコード番号, | |||
| @@ -100,18 +159,34 @@ const setData = (event: any, targets: string[]) => { | |||
| return event; | |||
| }); | |||
| kintone.events.on("app.record.create.submit.success", (event) => { | |||
| const record = event.record as 入金予定結果; | |||
| // 初回請求確定時にはメールを送信する | |||
| if ( | |||
| record[入金予定結果フィールド名.初回振り込み関連申込レコード番号].value | |||
| ) { | |||
| sendEmail(EmailID.申込受付, { | |||
| season_ticket_contract_entry_record_no: Number( | |||
| record[入金予定結果フィールド名.初回振り込み関連申込レコード番号] | |||
| .value | |||
| ), | |||
| }); | |||
| } | |||
| }); | |||
| kintone.events.on( | |||
| KintoneEvent.追加.保存するとき, | |||
| eventHnalder(async (event: any) => { | |||
| const record = event.record as 入金予定結果; | |||
| // 初回請求確定時にはメールを送信する | |||
| if ( | |||
| record[入金予定結果フィールド名.初回振り込み関連申込レコード番号].value | |||
| ) { | |||
| await 初回請求金額確定(record); | |||
| } | |||
| }) | |||
| ); | |||
| kintone.events.on( | |||
| KintoneEvent.追加.保存に成功した後, | |||
| eventHnalder(async (event: any) => { | |||
| const record = event.record as 入金予定結果; | |||
| // 初回請求確定時にはメールを送信する | |||
| if ( | |||
| record[入金予定結果フィールド名.初回振り込み関連申込レコード番号].value | |||
| ) { | |||
| // メール送信 | |||
| sendEmail(EmailID.申込受付, { | |||
| season_ticket_contract_entry_record_no: Number( | |||
| record[入金予定結果フィールド名.初回振り込み関連申込レコード番号] | |||
| .value | |||
| ), | |||
| }); | |||
| } | |||
| }) | |||
| ); | |||
| })(); | |||
| @@ -7,10 +7,11 @@ import { | |||
| SuccessDialog, | |||
| WarningDialog, | |||
| } from "@/middleware/swal"; | |||
| import { getCreateUrl } from "@/rest-api/url"; | |||
| import { getCreateUrl, getDetailUrl } from "@/rest-api/url"; | |||
| import { 入金予定結果フィールド名 } from "@/types/入金予定結果"; | |||
| import { 定期申込予約 } from "@/types/定期申込予約"; | |||
| import { 申込 } from "./自動承認"; | |||
| import { apptemplate } from "@/common/app-template"; | |||
| (() => { | |||
| console.info("script build at " + process.env.BUILD_TIME); | |||
| @@ -19,13 +20,14 @@ import { 申込 } from "./自動承認"; | |||
| const record: 定期申込予約 = event.record; | |||
| if (!record.auto_confirm_status.value) { | |||
| setHeaderButton("自動承認", async () => { | |||
| const confirm = await ShowConfirmDialog({ | |||
| text: "承認しますか", | |||
| }); | |||
| if (!confirm.isConfirmed) return; | |||
| setHeaderButton( | |||
| "自動承認", | |||
| apptemplate(async () => { | |||
| const confirm = await ShowConfirmDialog({ | |||
| text: "承認しますか", | |||
| }); | |||
| if (!confirm.isConfirmed) return; | |||
| try { | |||
| const entry = new 申込(record); | |||
| await entry.初期化(); | |||
| await entry.選定(); | |||
| @@ -45,25 +47,22 @@ import { 申込 } from "./自動承認"; | |||
| [入金予定結果フィールド名.初回振り込み関連申込レコード番号]: | |||
| record.$id.value, | |||
| }); | |||
| const url = getCreateUrl(AppID.入金予定結果, param); | |||
| console.log(url, param); | |||
| window.open(url, "_blank"); | |||
| { | |||
| // 入金予定アプリ画面オープン | |||
| const url = getCreateUrl(AppID.入金予定結果, param); | |||
| console.log(url, param); | |||
| window.open(url, "_blank"); | |||
| } | |||
| { | |||
| // 車室契約情報アプリ画面オープン | |||
| const url = getDetailUrl(AppID.車室契約情報, 契約.$id.value); | |||
| console.log(url, param); | |||
| window.open(url, "_blank"); | |||
| } | |||
| location.reload(); | |||
| } catch (e) { | |||
| if (e instanceof CancelError) { | |||
| console.log("canceled"); | |||
| return; | |||
| } else if (e instanceof Message) { | |||
| ErrorDialog.fire({ | |||
| text: e.message, | |||
| }); | |||
| return; | |||
| } | |||
| ErrorDialog.fire(); | |||
| throw e; | |||
| } | |||
| }); | |||
| }) | |||
| ); | |||
| } | |||
| }); | |||
| })(); | |||
| @@ -1,14 +1,10 @@ | |||
| import { AppID } from "@/common/appids"; | |||
| import { makeRecordData } from "@/common/rest-api-client"; | |||
| import { 契約状況同期 } from "@/logic/契約状況同期"; | |||
| import { | |||
| ConfirmDialog, | |||
| ShowConfirmDialog, | |||
| showLoadingDialog, | |||
| } from "@/middleware/swal"; | |||
| import { EmailID, sendEmail } from "@/mypage/メール"; | |||
| import { ShowConfirmDialog } from "@/middleware/swal"; | |||
| import { BulkRequest } from "@/rest-api/bulk"; | |||
| import { getDetailUrl } from "@/rest-api/url"; | |||
| import { get定期駐車場プランマスタ } from "@/rest-api/定期駐車場プランマスタ"; | |||
| import { get自動承認グループ } from "@/rest-api/自動承認グループ"; | |||
| import { get車室契約情報, get車室契約情報一覧 } from "@/rest-api/車室契約情報"; | |||
| import { get車室情報一覧 } from "@/rest-api/車室情報2"; | |||
| @@ -23,14 +19,13 @@ import { | |||
| 状態Dropdown, | |||
| 自動承認ステータスDropdown, | |||
| } from "@/types/定期申込予約"; | |||
| import { 定期駐車場プランマスタ } from "@/types/定期駐車場プランマスタ"; | |||
| import { 自動承認グループ } from "@/types/自動承認グループ"; | |||
| import { 車室契約情報, 車室契約情報フィールド名 } from "@/types/車室契約情報"; | |||
| import { 車室情報2 } from "@/types/車室情報2"; | |||
| import { 顧客マスタフィールド名 } from "@/types/顧客マスタ"; | |||
| import { sprintf } from "sprintf"; | |||
| import { CancelError, Message } from "../../exception"; | |||
| import { 入金予定結果フィールド名 } from "@/types/入金予定結果"; | |||
| import { dateParse, now } from "@/common/datetime"; | |||
| import { CancelError, Message } from "@/exception"; | |||
| export class 申込 { | |||
| private 定期申込予約: 定期申込予約; | |||
| @@ -43,6 +38,7 @@ export class 申込 { | |||
| private 車室一覧: 車室情報2[] = []; | |||
| private 契約一覧: 車室契約情報[] = []; | |||
| private 自動承認グループ: 自動承認グループ | null = null; | |||
| private プラン: 定期駐車場プランマスタ | null = null; | |||
| private 作成後契約: 車室契約情報 | null = null; | |||
| @@ -59,6 +55,8 @@ export class 申込 { | |||
| await this.契約情報取得(); | |||
| // 自動承認データの取得 | |||
| await this.自動承認グループ取得(); | |||
| // 定期駐車場プランマスタデータの取得 | |||
| await this.プラン取得(); | |||
| this.初期化済み = true; | |||
| return this; | |||
| @@ -117,6 +115,14 @@ export class 申込 { | |||
| this.定期申込予約.定期駐車場プラン.value | |||
| ); | |||
| } | |||
| private async プラン取得() { | |||
| if (!this.定期申込予約.定期駐車場プラン.value) { | |||
| throw new Message("プラン名の設定をしてください"); | |||
| } | |||
| this.プラン = await get定期駐車場プランマスタ( | |||
| this.定期申込予約.定期駐車場プラン.value | |||
| ); | |||
| } | |||
| private 対象車室取得() { | |||
| if (!this.初期化済み) { | |||
| @@ -227,6 +233,7 @@ export class 申込 { | |||
| } | |||
| private async 申込情報完了() { | |||
| if (this.プラン === null) throw new Error(); | |||
| const F = 定期申込予約フィールド名; | |||
| this.requests.update({ | |||
| app: AppID.定期申込予約, | |||
| @@ -234,6 +241,7 @@ export class 申込 { | |||
| record: makeRecordData({ | |||
| [F.状態]: 状態Dropdown.承認_自動承認, | |||
| [F.自動承認ステータス]: 自動承認ステータスDropdown.承認済, | |||
| [F.定期駐車料金]: this.プラン.契約金額.value, | |||
| }), | |||
| }); | |||
| } | |||
| @@ -0,0 +1,45 @@ | |||
| import { CancelError, Message } from "@/exception"; | |||
| import { ErrorDialog } from "@/middleware/swal"; | |||
| export const apptemplate = (callback: () => Promise<void>) => { | |||
| return async () => { | |||
| try { | |||
| const ret = await callback(); | |||
| } catch (e) { | |||
| if (e instanceof CancelError) { | |||
| console.log("canceled"); | |||
| return; | |||
| } else if (e instanceof Message) { | |||
| ErrorDialog.fire({ | |||
| text: e.message, | |||
| }); | |||
| return; | |||
| } | |||
| ErrorDialog.fire(); | |||
| throw e; | |||
| } | |||
| }; | |||
| }; | |||
| export const eventHnalder = (callback: (event: any) => Promise<any>) => { | |||
| return async (event: any) => { | |||
| try { | |||
| const ret = await callback(event); | |||
| return ret; | |||
| } catch (e) { | |||
| if (e instanceof CancelError) { | |||
| console.log("canceled"); | |||
| return false; | |||
| } else if (e instanceof Message) { | |||
| console.error("message", e.message); | |||
| ErrorDialog.fire({ | |||
| text: e.message, | |||
| }); | |||
| return false; | |||
| } | |||
| ErrorDialog.fire(); | |||
| console.error(e); | |||
| return false; | |||
| } | |||
| }; | |||
| }; | |||
| @@ -12,5 +12,6 @@ export const AppID = { | |||
| 車室契約情報: APP_ID.車室契約情報, | |||
| 車室情報2: APP_ID.車室情報2, | |||
| 自動承認グループ: APP_ID.自動承認グループ, | |||
| 定期駐車場プランマスタ: APP_ID.定期駐車場プランマスタ, | |||
| } as const; | |||
| export type AppID = (typeof AppID)[keyof typeof AppID]; | |||
| @@ -0,0 +1,39 @@ | |||
| export const KintoneEvent = { | |||
| 一覧: { | |||
| 一覧画面を表示した後: "app.record.index.show", | |||
| }, | |||
| 詳細: { | |||
| レコード詳細画面を表示した後: "app.record.detail.show", | |||
| レコードを削除する前: "app.record.detail.delete.submit", | |||
| プロセス管理のアクションを実行したとき: "app.record.detail.process.proceed", | |||
| }, | |||
| // レコード追加画面 | |||
| 追加: { | |||
| レコード追加画面を表示した後: "app.record.create.show", | |||
| 保存するとき: "app.record.create.submit", | |||
| 保存に成功した後: "app.record.create.submit.success", | |||
| }, | |||
| // レコード編集画面 | |||
| 編集: { | |||
| レコード編集画面を表示した後: "app.record.edit.show", | |||
| 保存するとき: "app.record.edit.show", | |||
| 保存に成功した後: "app.record.edit.success", | |||
| }, | |||
| } as const; | |||
| export const 画面遷移 = (event: any, url: string) => { | |||
| event.url = url; | |||
| }; | |||
| export const 値設定 = ( | |||
| event: any, | |||
| target: string, | |||
| value: any, | |||
| lookup: boolean = false | |||
| ) => { | |||
| event.record[target].value = value; | |||
| if (lookup) { | |||
| event.record[target].lookup = true; | |||
| } | |||
| }; | |||
| @@ -74,6 +74,7 @@ export class BulkRequest { | |||
| } | |||
| async save() { | |||
| this.debug(); | |||
| let results: BulkRequestResponse[] = []; | |||
| for (const requests of chunk(this.requests, 20)) { | |||
| const res = await this.client.bulkRequest({ requests }); | |||
| @@ -0,0 +1,16 @@ | |||
| import { AppID } from "@/common/appids"; | |||
| import { 定期申込予約 } from "@/types/定期申込予約"; | |||
| import { KintoneRestAPIClient } from "@kintone/rest-api-client"; | |||
| const client = new KintoneRestAPIClient(); | |||
| export const get定期申込予約 = async ( | |||
| レコード番号: string | number | |||
| ): Promise<定期申込予約> => { | |||
| const { record } = await client.record.getRecord<定期申込予約>({ | |||
| app: AppID.定期申込予約, | |||
| id: レコード番号, | |||
| }); | |||
| return record; | |||
| }; | |||
| @@ -0,0 +1,35 @@ | |||
| import { AppID } from "@/common/appids"; | |||
| import { | |||
| 定期駐車場プランマスタ, | |||
| 定期駐車場プランマスタフィールド名, | |||
| } from "@/types/定期駐車場プランマスタ"; | |||
| import { KintoneRestAPIClient } from "@kintone/rest-api-client"; | |||
| import { sprintf } from "sprintf"; | |||
| const client = new KintoneRestAPIClient(); | |||
| export const get定期駐車場プランマスタ = async ( | |||
| プラン名: string | |||
| ): Promise<定期駐車場プランマスタ> => { | |||
| const query = sprintf( | |||
| sprintf('%s = "%s"', 定期駐車場プランマスタフィールド名.プラン名, プラン名) | |||
| ); | |||
| const { records } = await client.record.getRecords<定期駐車場プランマスタ>({ | |||
| app: AppID.定期駐車場プランマスタ, | |||
| query, | |||
| }); | |||
| if (records.length !== 1) { | |||
| throw new Error( | |||
| sprintf( | |||
| "定期駐車場プランマスタ取得数数エラー expect %d, actual %d query:%s", | |||
| 1, | |||
| records.length, | |||
| query | |||
| ) | |||
| ); | |||
| } | |||
| return records[0]; | |||
| }; | |||
| @@ -5,6 +5,14 @@ const F = { | |||
| 状態: "status", | |||
| 自動承認ステータス: "auto_confirm_status", | |||
| 利用開始希望日: "利用開始希望日", | |||
| 定期駐車料金: "定期駐車料金", | |||
| 振込期日: "振込期日", | |||
| 日割り分_月: "日割り分_月", | |||
| 日割り分_金額: "日割り分_金額", | |||
| 請求対象分_月: "請求対象分_月", | |||
| 請求対象分_金額: "請求対象分_金額", | |||
| 初回振り込み合計額: "初回振り込み合計額", | |||
| } as const; | |||
| export const 状態Dropdown = { | |||
| @@ -38,12 +46,12 @@ export type 定期申込予約 = AppRecord & { | |||
| 台数: KintoneRecordField.SingleLineText; | |||
| 防犯登録番号: KintoneRecordField.SingleLineText; | |||
| 請求対象分_月: KintoneRecordField.Number; | |||
| 初回振り込み合計額: KintoneRecordField.Number; | |||
| [F.初回振り込み合計額]: KintoneRecordField.Number; | |||
| メールアドレス: KintoneRecordField.SingleLineText; | |||
| 受付日時: KintoneRecordField.DateTime; | |||
| 学生手帳: KintoneRecordField.SingleLineText; | |||
| 氏名: KintoneRecordField.SingleLineText; | |||
| 定期駐車料金: KintoneRecordField.Number; | |||
| [F.定期駐車料金]: KintoneRecordField.Number; | |||
| 学校名: KintoneRecordField.SingleLineText; | |||
| 住所: KintoneRecordField.SingleLineText; | |||
| 電話番号: KintoneRecordField.SingleLineText; | |||
| @@ -55,13 +63,13 @@ export type 定期申込予約 = AppRecord & { | |||
| 車室番号: KintoneRecordField.SingleLineText; | |||
| ParkingNavi駐車場: KintoneRecordField.SingleLineText; | |||
| 駐車場: KintoneRecordField.SingleLineText; | |||
| 振込期日: KintoneRecordField.Date; | |||
| [F.振込期日]: KintoneRecordField.Date; | |||
| 日割り分_金額: KintoneRecordField.Number; | |||
| 自動承認メモ: KintoneRecordField.MultiLineText; | |||
| 車両番号: KintoneRecordField.SingleLineText; | |||
| 請求対象分_金額: KintoneRecordField.Number; | |||
| [F.請求対象分_金額]: KintoneRecordField.Number; | |||
| ParkingNaviプラン: KintoneRecordField.SingleLineText; | |||
| 日割り分_月: KintoneRecordField.Number; | |||
| [F.日割り分_月]: KintoneRecordField.Number; | |||
| 支払方法: KintoneRecordField.Dropdown; | |||
| [F.自動承認ステータス]: KintoneRecordField.SingleLineText; | |||
| [F.状態]: KintoneRecordField.Dropdown; | |||