/// 価格設定のヘルパー関数群 /// /// 店員の感覚に寄り添った価格処理を提供します: /// - スマート丸め処理 (キリの良い価格に自動調整) /// - サイズ別価格の自動計算 /// - 価格表示フォーマット (カンマ区切り、円表記) class PricingHelper { /// サイズ別の価格比率 /// /// 店員が感覚的に使っている「一合を基準にした比率」 static const sizeRatios = { '45ml': 0.40, // 一合の約1/4 '90ml': 0.65, // 一合の半分弱 '180ml': 1.0, // 基準 (一合) }; /// スマート丸め処理 /// /// 店員が手作業でやる「端数を切る」処理を自動化。 /// 価格帯に応じて、キリの良い単位に丸めます: /// - 500円未満: 50円単位 (例: 720円 → 700円) /// - 500円以上: 100円単位 (例: 1,170円 → 1,200円) /// /// [rawPrice] 計算された生の価格 /// 戻り値: 丸められた価格 static int smartRound(double rawPrice) { if (rawPrice <= 0) return 0; if (rawPrice < 500) { // 500円未満 → 50円単位 return ((rawPrice / 50).round() * 50).toInt(); } else { // 500円以上 → 100円単位 return ((rawPrice / 100).round() * 100).toInt(); } } /// サイズ別価格の計算 /// /// 一合価格を基準に、各サイズの価格を自動計算します。 /// /// [basePrice] 一合 (180ml) の価格 /// [size] サイズ (45ml, 90ml, 180ml) /// 戻り値: 計算・丸め処理された価格 static int calculateSizePrice(int basePrice, String size) { final ratio = sizeRatios[size] ?? 1.0; final rawPrice = basePrice * ratio; return smartRound(rawPrice); } /// 価格フォーマット (カンマ区切り) /// /// 内部データ (int) を表示用文字列に変換します: /// - 3桁ごとにカンマを挿入 /// - 「円」は付けない (表示側で追加) /// /// [price] 価格 (int) /// 戻り値: カンマ区切りの文字列 (例: "1,800") static String formatPrice(int price) { if (price <= 0) return '0'; return price.toString().replaceAllMapped( RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},', ); } /// 価格パース (カンマ除去) /// /// ユーザー入力 (カンマ付き文字列) を int に変換します。 /// /// [priceString] 価格文字列 (例: "1,800" or "1800") /// 戻り値: パースされた価格 (失敗時は null) static int? parsePrice(String priceString) { final cleaned = priceString.replaceAll(',', '').trim(); return int.tryParse(cleaned); } /// サイズ表示名 /// /// 内部ID (45ml) を表示用の名称に変換します。 /// /// [size] サイズID /// 戻り値: 表示名 (例: "45ml") static String getSizeDisplayName(String size) { // 現状はそのまま返すが、将来的に「グラス (45ml)」などに拡張可能 return size; } /// 利用可能なサイズ一覧 /// /// MVPで提供するサイズの一覧。 /// デモでは3種類に絞る。 static List get availableSizes => ['45ml', '90ml', '180ml']; }