From 1a43f93f88a2cbe132285f64e32c408a6ae49671 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Fri, 8 Dec 2023 14:27:45 +0900 Subject: [PATCH] =?UTF-8?q?=E5=90=84=E7=A8=AE=E7=94=B3=E8=AB=8B=E3=80=80?= =?UTF-8?q?=E5=8F=A3=E5=BA=A7=E5=A4=89=E6=9B=B4=E7=94=B3=E8=AB=8B=E3=81=AE?= =?UTF-8?q?=E6=89=BF=E8=AA=8D=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + src/apps/各種申請/customize-manifest.json | 12 ++ src/apps/各種申請/index.tsx | 144 ++++++++++++++++++ src/common/appids.ts | 14 +- src/common/timer.ts | 3 + src/config/kintone.ts | 37 +++++ src/middleware/swal.ts | 49 +++++- src/rest-api/顧客マスタ.ts | 47 ++++++ src/types/各種申請.ts | 110 +++++++++++++ src/types/顧客マスタ.ts | 77 ++++++++++ yarn.lock | 10 ++ 11 files changed, 497 insertions(+), 8 deletions(-) create mode 100644 src/apps/各種申請/customize-manifest.json create mode 100644 src/apps/各種申請/index.tsx create mode 100644 src/common/timer.ts create mode 100644 src/config/kintone.ts create mode 100644 src/rest-api/顧客マスタ.ts create mode 100644 src/types/各種申請.ts create mode 100644 src/types/顧客マスタ.ts diff --git a/package.json b/package.json index 7eb7b0b..a68a026 100644 --- a/package.json +++ b/package.json @@ -46,11 +46,13 @@ }, "dependencies": { "@kintone/rest-api-client": "^2.0.17", + "@types/sprintf": "^0.1.2", "core-js": "^3.6.4", "date-fns": "^2.30.0", "kintone-ui-component": "^1.14.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "sprintf": "^0.1.5", "sweetalert2": "^11.10.1", "sweetalert2-react-content": "^5.0.7" } diff --git a/src/apps/各種申請/customize-manifest.json b/src/apps/各種申請/customize-manifest.json new file mode 100644 index 0000000..a3284c4 --- /dev/null +++ b/src/apps/各種申請/customize-manifest.json @@ -0,0 +1,12 @@ +{ + "app": "294", + "scope": "ALL", + "desktop": { + "js": ["dist/各種申請.js"], + "css":[] + }, + "mobile": { + "js": [], + "css":[] + } +} diff --git a/src/apps/各種申請/index.tsx b/src/apps/各種申請/index.tsx new file mode 100644 index 0000000..525a763 --- /dev/null +++ b/src/apps/各種申請/index.tsx @@ -0,0 +1,144 @@ +import { AppID } from "@/common/appids"; +import { setHeaderButton } from "@/common/header-button"; +import { makeRecordData } from "@/common/rest-api-client"; +import { delay } from "@/common/timer"; +import { + ConfirmDialog, + ErrorDialog, + LoadingDialog, + SuccessDialog, + closeLoading, + showLoading, +} from "@/middleware/swal"; +import { get顧客マスタ } from "@/rest-api/顧客マスタ"; +import { + 各種申請, + 各種申請フィールド名, + 状況Dropdown, + 申請種別Dropdown, +} from "@/types/各種申請"; +import { 顧客マスタフィールド名 } from "@/types/顧客マスタ"; +import { KintoneRestAPIClient } from "@kintone/rest-api-client"; + +const client = new KintoneRestAPIClient(); + +const 各種申請完了 = (record: 各種申請) => { + return client.record.updateRecord({ + app: AppID.各種申請, + id: record.$id.value, + record: makeRecordData({ + [各種申請フィールド名.状況]: 状況Dropdown.完了, + }), + }); +}; + +const 口座変更申請承認 = async (record: 各種申請) => { + const customer = await get顧客マスタ({ + 顧客コード: Number(record.顧客コード.value), + }); + + // 顧客マスタへの反映 + await client.record.updateRecord({ + app: AppID.顧客マスタ, + id: customer.$id.value, + record: makeRecordData({ + [顧客マスタフィールド名.口座登録催促予定日時]: "", + [顧客マスタフィールド名.銀行支店コード]: + record.口座変更申請_変更後_銀行支店ID.value, + [顧客マスタフィールド名.引落預金種別]: + record.口座変更申請_変更後_口座種目.value, + [顧客マスタフィールド名.引落口座名義人カナ]: + record.口座変更申請_変更後_口座名義カナ.value, + [顧客マスタフィールド名.引落口座番号]: + record.口座変更申請_変更後_口座番号.value, + [顧客マスタフィールド名.ゆうちょ口座記号]: + record.口座変更申請_変更後_ゆうちょ口座記号.value, + [顧客マスタフィールド名.ゆうちょ口座番号]: + record.口座変更申請_変更後_ゆうちょ口座番号.value, + }), + }); + + // 各種申請の完了 + await 各種申請完了(record); +}; + +const getCallBack口座変更申請承認 = (record: 各種申請) => { + return async () => { + const confirm = await ConfirmDialog.fire({ + title: "承認しますか", + }); + if (!confirm.isConfirmed) return; + + try { + showLoading(); + 口座変更申請承認(record); + closeLoading(); + } catch (e) { + console.error(e); + closeLoading(); + ErrorDialog.fire(); + return; + } + + SuccessDialog.fire().then(() => { + location.reload(); + }); + }; +}; + +const 解約申請承認 = async (record: 各種申請) => { + const customer = await get顧客マスタ({ + 顧客コード: Number(record.顧客コード.value), + }); + + // 車室契約情報への反映 +}; + +const getCallBack解約申請承認 = (record: 各種申請) => { + return async () => { + const confirm = await ConfirmDialog.fire({ + title: "承認しますか", + }); + if (!confirm.isConfirmed) return; + + try { + showLoading(); + 口座変更申請承認(record); + closeLoading(); + } catch (e) { + console.error(e); + closeLoading(); + ErrorDialog.fire(); + return; + } + + SuccessDialog.fire().then(() => { + location.reload(); + }); + }; +}; + +(() => { + console.info("script build at " + process.env.BUILD_TIME); + + kintone.events.on("app.record.detail.show", (event) => { + const currentRecord = event.record as 各種申請; + + // 各種ボタンの設置 + if ( + currentRecord.状況.value !== 状況Dropdown.完了 && + currentRecord.申請種別.value === 申請種別Dropdown.口座変更申請 + ) { + setHeaderButton( + "口座変更申請 承認", + getCallBack口座変更申請承認(currentRecord) + ); + } + if ( + currentRecord.状況.value !== 状況Dropdown.完了 && + currentRecord.申請種別.value === 申請種別Dropdown.解約申請 + ) { + setHeaderButton("解約申請 承認", getCallBack解約申請承認(currentRecord)); + } + }); +})(); diff --git a/src/common/appids.ts b/src/common/appids.ts index c2256ca..6df4214 100644 --- a/src/common/appids.ts +++ b/src/common/appids.ts @@ -1,7 +1,13 @@ +import { KintoneConfig } from "@/config/kintone"; + +const { APP_ID } = KintoneConfig(); + export const AppID = { - 定期申込予約: 271, - 定期予約選考: 301, - 問い合わせ: 291, - 入金予定結果: 272, + 顧客マスタ: APP_ID.顧客マスタ, + 定期申込予約: APP_ID.定期申込予約, + 定期予約選考: APP_ID.定期予約選考, + 問い合わせ: APP_ID.問い合わせ, + 入金予定結果: APP_ID.入金予定結果, + 各種申請: APP_ID.各種申請, } as const; export type AppID = (typeof AppID)[keyof typeof AppID]; diff --git a/src/common/timer.ts b/src/common/timer.ts new file mode 100644 index 0000000..6b8c676 --- /dev/null +++ b/src/common/timer.ts @@ -0,0 +1,3 @@ +export const delay = (milisec: number) => { + return new Promise((resolve) => setTimeout(resolve, milisec)); +}; diff --git a/src/config/kintone.ts b/src/config/kintone.ts new file mode 100644 index 0000000..b8111ae --- /dev/null +++ b/src/config/kintone.ts @@ -0,0 +1,37 @@ +export type KintoneConfig = { + APP_ID: { + 顧客マスタ: number; + 定期申込予約: number; + 定期予約選考: number; + 問い合わせ: number; + 入金予定結果: number; + 各種申請: number; + }; +}; + +export const KintoneConfig = (): KintoneConfig => { + if (process.env.NODE_ENV === "development") { + return { + APP_ID: { + 顧客マスタ: 254, + 定期申込予約: 271, + 定期予約選考: 301, + 問い合わせ: 291, + 入金予定結果: 272, + 各種申請: 294, + }, + }; + } else { + throw new Error("KintoneConfig不正"); + return { + APP_ID: { + 顧客マスタ: 254, + 定期申込予約: 271, + 定期予約選考: 301, + 問い合わせ: 291, + 入金予定結果: 272, + 各種申請: 294, + }, + }; + } +}; diff --git a/src/middleware/swal.ts b/src/middleware/swal.ts index 5e1c7e1..3ee98b4 100644 --- a/src/middleware/swal.ts +++ b/src/middleware/swal.ts @@ -1,5 +1,46 @@ -import S from "sweetalert2"; -import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; -const Swal = withReactContent(S); -export default Swal; +export const SuccessDialog = Swal.mixin({ + icon: "success", + timer: 1000, + title: "成功しました", +}); + +export const ErrorDialog = Swal.mixin({ + icon: "error", + title: "エラーが発生しました", +}); + +export const ConfirmDialog = Swal.mixin({ + icon: "info", + showCancelButton: true, + confirmButtonText: "実行", + cancelButtonText: "キャンセル", +}); + +export const LoadingDialog = Swal.mixin({ + title: "実行中...", + text: "画面を閉じないでください", + allowOutsideClick: false, + allowEscapeKey: false, + allowEnterKey: false, + didOpen() { + Swal.showLoading(); + }, +}); + +export const showLoading = (timer: number = 5000) => { + LoadingDialog.fire({ + timer, + }).then((result) => { + if (result.dismiss === Swal.DismissReason.timer) { + ErrorDialog.fire({ + title: "処理タイムアウトしました", + }); + } + }); +}; + +export const closeLoading = () => { + Swal.close(); +}; diff --git a/src/rest-api/顧客マスタ.ts b/src/rest-api/顧客マスタ.ts new file mode 100644 index 0000000..37dbf7e --- /dev/null +++ b/src/rest-api/顧客マスタ.ts @@ -0,0 +1,47 @@ +import { AppID } from "@/common/appids"; +import { 顧客マスタ, 顧客マスタフィールド名 } from "@/types/顧客マスタ"; +import { KintoneRestAPIClient } from "@kintone/rest-api-client"; +import { sprintf } from "sprintf"; + +const client = new KintoneRestAPIClient(); + +type Props = { + レコード番号?: number; + 顧客コード?: number; +}; +export const get顧客マスタ = async ({ + レコード番号, + 顧客コード, +}: Props): Promise<顧客マスタ> => { + if (!!レコード番号) { + const { record } = await client.record.getRecord<顧客マスタ>({ + app: AppID.顧客マスタ, + id: レコード番号, + }); + + return record; + } + if (!!顧客コード) { + const query = sprintf( + sprintf("%s = %d", 顧客マスタフィールド名.顧客コード, 顧客コード) + ); + + const { records } = await client.record.getRecords<顧客マスタ>({ + app: AppID.顧客マスタ, + query, + }); + + if (records.length !== 1) { + throw new Error( + sprintf( + "顧客マスタ取得数エラー expect %d, actual %d", + 1, + records.length + ) + ); + } + return records[0]; + } + + throw new Error("get顧客マスタ 引数エラー"); +}; diff --git a/src/types/各種申請.ts b/src/types/各種申請.ts new file mode 100644 index 0000000..09b09ac --- /dev/null +++ b/src/types/各種申請.ts @@ -0,0 +1,110 @@ +import { KintoneRecordField } from "@kintone/rest-api-client"; +import { AppRecord } from "."; + +const F = { + 申請種別: "申請種別", + 申請番号: "申請番号", + 状況: "状況", +} as const; + +export const 状況Dropdown = { + 新規登録: "新規登録", + 処理中: "処理中", + 完了: "完了", +} as const; +export type 状況Dropdown = (typeof 状況Dropdown)[keyof typeof 状況Dropdown]; + +export const 申請種別Dropdown = { + 解約申請: "解約申請", + 車庫証明発行申請: "車庫証明発行申請", + シール再発行申請: "シール再発行申請", + 定期券再発行申請: "定期券再発行申請", + 車両番号_防犯登録番号変更: "車両番号・防犯登録番号変更", + 利用者情報変更: "利用者情報変更", + 口座変更申請: "口座変更申請", + プラン変更: "プラン変更", +} as const; +export type 申請種別Dropdown = + (typeof 申請種別Dropdown)[keyof typeof 申請種別Dropdown]; + +export const 各種申請フィールド名 = F; + +export type 各種申請 = AppRecord & { + シール再発行申請_再発行理由: KintoneRecordField.MultiLineText; + シール再発行申請_備考: KintoneRecordField.MultiLineText; + プラン変更申請_備考: KintoneRecordField.MultiLineText; + プラン変更申請_変更後_プラン名: KintoneRecordField.SingleLineText; + プラン変更申請_変更前_プラン名: KintoneRecordField.SingleLineText; + 解約申請_意見: KintoneRecordField.MultiLineText; + 解約申請_解約希望日: KintoneRecordField.Date; + 解約申請_解約理由_詳細: KintoneRecordField.MultiLineText; + 解約申請_解約理由: KintoneRecordField.CheckBox; + 解約申請_備考: KintoneRecordField.MultiLineText; + 契約情報: KintoneRecordField.Number; + 契約駐車場: KintoneRecordField.SingleLineText; + 顧客コード: KintoneRecordField.Number; + 顧客名: KintoneRecordField.SingleLineText; + 顧客名カナ: KintoneRecordField.SingleLineText; + 口座変更申請_SMBC結果: KintoneRecordField.SingleLineText; + 口座変更申請_SMBC受付番号: KintoneRecordField.SingleLineText; + 口座変更申請_SMBC申請日時: KintoneRecordField.DateTime; + 口座変更申請_顧客コード: KintoneRecordField.Number; + 口座変更申請_変更後_ゆうちょ口座記号: KintoneRecordField.Number; + 口座変更申請_変更後_ゆうちょ口座番号: KintoneRecordField.Number; + 口座変更申請_変更後_金融機関コード: KintoneRecordField.SingleLineText; + 口座変更申請_変更後_金融機関名: KintoneRecordField.SingleLineText; + 口座変更申請_変更後_銀行支店ID: KintoneRecordField.SingleLineText; + 口座変更申請_変更後_口座種目: KintoneRecordField.Number; + 口座変更申請_変更後_口座番号: KintoneRecordField.Number; + 口座変更申請_変更後_口座名義カナ: KintoneRecordField.SingleLineText; + 口座変更申請_変更後_支店コード: KintoneRecordField.SingleLineText; + 口座変更申請_変更後_支店名: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_ゆうちょ口座記号: KintoneRecordField.Number; + 口座変更申請_変更前_ゆうちょ口座番号: KintoneRecordField.Number; + 口座変更申請_変更前_金融機関コード: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_金融機関名: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_銀行支店ID: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_口座種目: KintoneRecordField.Number; + 口座変更申請_変更前_口座番号: KintoneRecordField.Number; + 口座変更申請_変更前_口座名義カナ: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_支店コード: KintoneRecordField.SingleLineText; + 口座変更申請_変更前_支店名: KintoneRecordField.SingleLineText; + 車庫証明発行申請_支払方法: KintoneRecordField.Dropdown; + 車庫証明発行申請_氏名: KintoneRecordField.SingleLineText; + 車庫証明発行申請_車体番号: KintoneRecordField.SingleLineText; + 車庫証明発行申請_車両番号: KintoneRecordField.SingleLineText; + 車庫証明発行申請_住所: KintoneRecordField.SingleLineText; + 車庫証明発行申請_電話番号: KintoneRecordField.SingleLineText; + 車庫証明発行申請_備考: KintoneRecordField.MultiLineText; + 車庫証明発行申請_郵送先_宛名: KintoneRecordField.SingleLineText; + 車庫証明発行申請_郵送先_住所: KintoneRecordField.SingleLineText; + 車庫証明発行申請_郵送先_郵便番号: KintoneRecordField.SingleLineText; + 車庫証明発行申請_郵便番号: KintoneRecordField.SingleLineText; + 車両番号_防犯番号変更申請_備考: KintoneRecordField.MultiLineText; + 車両番号_防犯番号変更申請_変更後_車両番号: KintoneRecordField.SingleLineText; + 車両番号_防犯番号変更申請_変更後_防犯登録番号: KintoneRecordField.SingleLineText; + 車両番号_防犯番号変更申請_変更前_車両番号: KintoneRecordField.SingleLineText; + 車両番号_防犯番号変更申請_変更前_防犯登録番号: KintoneRecordField.SingleLineText; + 車両番号_防犯番号変更申請_変更日: KintoneRecordField.Date; + 車両番号: KintoneRecordField.SingleLineText; + [F.状況]: KintoneRecordField.Dropdown; + 申請種別: KintoneRecordField.Dropdown; + 申請日時: KintoneRecordField.DateTime; + 申請番号: KintoneRecordField.SingleLineText; + 担当者: KintoneRecordField.UserSelect; + 駐車場名: KintoneRecordField.SingleLineText; + 定期券再発行申請_再発行理由: KintoneRecordField.MultiLineText; + 定期券再発行申請_備考: KintoneRecordField.MultiLineText; + 定期券番号: KintoneRecordField.SingleLineText; + 利用者情報変更申請_備考: KintoneRecordField.MultiLineText; + 利用者情報変更申請_変更後_氏名: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更後_氏名カナ: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更後_住所: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更後_電話番号: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更後_郵便番号: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更前_氏名: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更前_氏名カナ: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更前_住所: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更前_電話番号: KintoneRecordField.SingleLineText; + 利用者情報変更申請_変更前_郵便番号: KintoneRecordField.SingleLineText; +}; diff --git a/src/types/顧客マスタ.ts b/src/types/顧客マスタ.ts new file mode 100644 index 0000000..05d4ed0 --- /dev/null +++ b/src/types/顧客マスタ.ts @@ -0,0 +1,77 @@ +import { KintoneRecordField } from "@kintone/rest-api-client"; +import { AppRecord } from "."; + +const F = { + 顧客コード: "CustomerCode", + 銀行支店コード: "ChargedBankBranchCode", + 引落預金種別: "ChargedDepositType", + 引落口座名義人カナ: "ChargedAccountsKana", + 引落口座番号: "ChargedAccountsNo", + ゆうちょ口座記号: "YuchoAccountsSymbol", + ゆうちょ口座番号: "YuchoAccountsNo", + 口座登録催促予定日時: "口座登録催促予定日時", +} as const; + +// export const 支払種別Dropdown = { +// 定期料金: "定期料金", +// 保証金: "保証金", +// 証明書郵送代: "証明書郵送代", +// 事務手数料: "事務手数料", +// 延滞金: "延滞金", +// 余剰金: "余剰金", +// } as const; +// export type 支払種別Dropdown = +// (typeof 支払種別Dropdown)[keyof typeof 支払種別Dropdown]; + +export const 顧客マスタフィールド名 = F; + +export type 顧客マスタ = AppRecord & { + [F.引落口座名義人カナ]: KintoneRecordField.SingleLineText; + [F.引落口座番号]: KintoneRecordField.Number; + [F.銀行支店コード]: KintoneRecordField.SingleLineText; + ChargedBankCode: KintoneRecordField.SingleLineText; + ChargedBankName: KintoneRecordField.SingleLineText; + ChargedBranchCode: KintoneRecordField.SingleLineText; + ChargedBranchName: KintoneRecordField.SingleLineText; + [F.引落預金種別]: KintoneRecordField.Number; + ContractNo: KintoneRecordField.SingleLineText; + [F.顧客コード]: KintoneRecordField.Number; + CustomerName: KintoneRecordField.SingleLineText; + SMBC口座名義_1: KintoneRecordField.SingleLineText; + SMBC処理完了: KintoneRecordField.Dropdown; + SMBC入金額: KintoneRecordField.Number; + [F.ゆうちょ口座記号]: KintoneRecordField.Number; + [F.ゆうちょ口座番号]: KintoneRecordField.Number; + クレジット入金額: KintoneRecordField.Number; + コンビニ払入金額: KintoneRecordField.Number; + メールアドレス: KintoneRecordField.Link; + ゆうちょ口座名義_0: KintoneRecordField.SingleLineText; + ゆうちょ口座名義_1: KintoneRecordField.SingleLineText; + ゆうちょ口座名義: KintoneRecordField.SingleLineText; + ゆうちょ入金額: KintoneRecordField.Number; + 依頼日: KintoneRecordField.Date; + 契約者_郵便番号: KintoneRecordField.SingleLineText; + 顧客名カナ: KintoneRecordField.SingleLineText; + 口座振替依頼書: KintoneRecordField.File; + 口座登録催促予定日時: KintoneRecordField.DateTime; + 支払方法: KintoneRecordField.SingleLineText; + 住所: KintoneRecordField.SingleLineText; + 送付方法: KintoneRecordField.Dropdown; + 台数: KintoneRecordField.Number; + 長期未納者チェック_テスト: KintoneRecordField.CheckBox; + 電話番号2: KintoneRecordField.Link; + 電話番号3: KintoneRecordField.Link; + 電話番号: KintoneRecordField.Link; + 年額: KintoneRecordField.Number; + 年度入金コンビニ払額: KintoneRecordField.Number; + 年度入金引落額: KintoneRecordField.Number; + 年度入金振込額: KintoneRecordField.Number; + 年度入金累計: KintoneRecordField.Calc; + 備考_SMBC: KintoneRecordField.SingleLineText; + 備考: KintoneRecordField.MultiLineText; + 返却締日: KintoneRecordField.Date; + 未収金額: KintoneRecordField.Number; + 領収書: KintoneRecordField.Dropdown; + 領収書名_入力: KintoneRecordField.SingleLineText; + 領収書名: KintoneRecordField.SingleLineText; +}; diff --git a/yarn.lock b/yarn.lock index ec29ff6..e3f874d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1375,6 +1375,11 @@ dependencies: "@types/node" "*" +"@types/sprintf@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/sprintf/-/sprintf-0.1.2.tgz#507135e12592654dc6a6a2c2205d863b3049b772" + integrity sha512-uyDqLSXsTcoS5qV2ivIFtckLaoscEAeYV6/aPKBC8sUBUKQDLaMD3huA9q7eKIaiq6rrYHI5pmjIG4el6o5pcw== + "@types/trusted-types@^2.0.2": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" @@ -5543,6 +5548,11 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +sprintf@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/sprintf/-/sprintf-0.1.5.tgz#8f83e39a9317c1a502cb7db8050e51c679f6edcf" + integrity sha512-4X5KsuXFQ7f+d7Y+bi4qSb6eI+YoifDTGr0MQJXRoYO7BO7evfRCjds6kk3z7l5CiJYxgDN1x5Er4WiyCt+zTQ== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"