-
Notifications
You must be signed in to change notification settings - Fork 45
【チャレンジ課題】電気料金を返すAPIの実装 monakam01 #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 26 commits
ce0d022
f0863ab
5408876
51405de
eaadf5a
4970ab2
74a4b2f
771639c
46c3d9f
ec7f650
4cc5b0e
8eb6b5c
e897b3c
f535198
2371165
061e019
2cdbfd2
5909b8b
78237d9
b9f9e59
14325c5
e48eade
56818cc
5f7d63e
517b890
519b5a6
db2b5d6
e1890a7
a0d952f
18d89ba
ce69d19
344ac7d
f437eb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| Documentation: | ||
| Enabled: false | ||
| MethodLength: | ||
| CountComments: true | ||
| Max: 25 | ||
| Style/FrozenStringLiteralComment: | ||
| Enabled: false | ||
| Metrics: | ||
| Enabled: false | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Api | ||
| module V1 | ||
| class PowerSupplyPlanController < ApplicationController | ||
| def simulate_all | ||
| amp = params[:amp] | ||
| meter_rate = params[:meter_rate] | ||
| bad_request_result = build_200_message(amp, meter_rate) | ||
| return render json: bad_request_result, status: 400 if bad_request_result.present? | ||
|
|
||
| amp = amp.to_i | ||
| meter_rate = meter_rate.to_i | ||
| plans = PowerSupplyPlan.all | ||
| result = [] | ||
| plans.each do |plan| | ||
| basic_charge = plan.basic_charges.where(amp: amp) | ||
| next if basic_charge.blank? | ||
|
|
||
| meter_charge_price = meter_charge(plan, meter_rate) | ||
| next if meter_charge_price.negative? | ||
|
|
||
| result << { | ||
| provider_name: plan.provider.name, | ||
| plan_name: plan.name.to_s, | ||
| price: (basic_charge.first.price.to_f + meter_charge_price).floor(0).to_i | ||
| } | ||
| end | ||
| render json: result | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def meter_charge(plan, meter_rate) | ||
| price = 0 | ||
| plan.meter_rate_charges.each do |step| | ||
| price += calculate_if_step_applicable(step, meter_rate) | ||
| end | ||
| price | ||
| end | ||
|
|
||
| def calculate_if_step_applicable(step, meter_rate) | ||
| max_rate = step.max_meter_rate | ||
| min_rate = step.min_meter_rate | ||
| price = step.price | ||
|
|
||
|
|
||
| # 最小ステップ かつ 最大ステップ(従量料金設定が1ステップのみのケース) | ||
| return meter_rate * price if min_rate.zero? && max_rate.nil? | ||
|
|
||
| # 使用量がステップ請求額に満たない場合0を返す | ||
| return 0 if meter_rate < min_rate | ||
|
||
| if max_rate.nil? && min_rate <= meter_rate | ||
| # 最大料金ステップの計算 | ||
| return (meter_rate - min_rate + 1) * price | ||
| end | ||
|
|
||
| if min_rate.zero? | ||
| # 最小料金ステップの計算 | ||
| if max_rate <= meter_rate | ||
| # 該当ステップの満額請求計算 | ||
| max_rate * price | ||
| else | ||
| # 該当ステップの使用量までを計算 | ||
| meter_rate * price | ||
| end | ||
| elsif (min_rate..max_rate).include?(meter_rate) | ||
| # 中間料金ステップの計算 | ||
| # 該当ステップの使用量までを計算 | ||
| (meter_rate - min_rate + 1) * price | ||
| else | ||
| # 該当ステップの満額請求計算 | ||
| (max_rate - min_rate + 1) * price | ||
| end | ||
| end | ||
|
||
|
|
||
| def build_200_message(amp, meter_rate) | ||
|
||
| message = '' | ||
| if amp.blank? | ||
| message += "リクエストパラメータ 'amp' が不足しています。\n" | ||
| else | ||
| unless valid_amp?(amp) | ||
| message += "リクエストパラメータ 'amp' の値が不正です。'10 / 15 / 20 / 30 / 40 / 50 / 60' のいずれかの値を指定してください。\n" | ||
| end | ||
| end | ||
| if meter_rate.blank? | ||
| message += "リクエストパラメータ 'meter_rate' が不足しています。\n" | ||
| else | ||
| unless numeric?(meter_rate) && meter_rate.to_i >= 0 | ||
| message += "リクエストパラメータ 'meter_rate' の値が不正です。0以上の整数を指定してください。\n" | ||
| end | ||
| end | ||
| return errro_result(message) if message.present? | ||
|
|
||
| [] | ||
| end | ||
|
|
||
| def numeric?(string) | ||
| Integer(string) | ||
| true | ||
| rescue ArgumentError, TypeError | ||
| false | ||
| end | ||
|
|
||
| def valid_amp?(amp) | ||
| [10, 15, 20, 30, 40, 50, 60].include?(amp.to_i) | ||
|
||
| end | ||
|
|
||
| def errro_result(result) | ||
|
||
| [ | ||
| { | ||
| error: { | ||
| code: 400, | ||
| message: result | ||
| } | ||
| } | ||
| ] | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class BasicCharge < ApplicationRecord | ||
| belongs_to :power_supply_plan | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class MeterRateCharge < ApplicationRecord | ||
| belongs_to :power_supply_plan | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class PowerSupplyPlan < ApplicationRecord | ||
| belongs_to :provider | ||
| has_many :meter_rate_charges | ||
| has_many :basic_charges | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class Provider < ApplicationRecord | ||
| has_many :power_supply_plans | ||
| end |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. credentialsはどこにも使用されていなさそうです。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 追加項目 の本番デプロイ対応のためmaster.key とセットで追加しておりました。 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| bZE5VzGsIQoeBEOa79I28cq/Ax0SuIaPhy5+NFktLVZLNGpuzqmkTkAiWc+arbGUDU8aaedg9zUvnBBc0dPrATeWISHtFxVwJMScZQeSW1k7BUgSD6B6YsewlgtpEDFDAXoGZEQoTbM2FY3lDCd0dZF7I1+DsB4I9Z5NamOgOlNEK8gMQD3p3Csqc/mVhmdI3PjBEmblvTjkZIVOdfX1CmqJ/RZm1Lxu3RdNMaiXiOZL7I+oXE1SFfjWm7+CTwb+Vfs6nGMviDHDKh9k3jyb7Vflpx/frY4vYzP8WMzgbJPX4UHmxa7qS51tJ1ECpK265nS1mLsqxL7wRbjyzfUNtXknSSopGD7sDDm7F9ta8/e1nzU79uTH1LKFpWQWGMSbXmSu4EKPu655BA9ckdwnSsf67RYNX7/Nw5pp--9AT1V0z/SBAdVTZ5--JK/4x776vcnN7qGZuylM0g== | ||
| aLpSiYFmK7YeuO/q62KJR/UyXPpBWhH+oS6rzGWSQH/9p53vCpRMvfaUsZSneP9wYMioohjDqHdeY0bpOAXjMPy5suQk7yGANivapLmd2qNLt1wpIYzKGJiEwSP2gQD4Hyo/K6qGF2fchngDFhy0WWAe8Q0kcIM7WzUSV+VilcYylHcHHpdYhjsBx4+7ev2dbWLlYxbYuFSDGklGP85oYBmIH2QIzcYmwHhBkjwzFWvIl3xqL+/8iQlYsFyBsTk3tntgD/Au3kv6qYXQnf3ITXgHTKlaooxLTy9ZYwMOhJvPwtkMsWv9CVY+ACkUi5h9WY+rSHiBVCDHJwnEhwpz8/n4kzGXLuGRburdDZkA1IZb+j7+KzX625Y+x4+zR7P1wc8vJRw+/5O4MSndI28y0KkX15Qd8vMYNrowsXx+0WFtvo8LTh0J6p84b4bJyVkD1bGUpvpz+UADtGfTbuDqqRXNDCRM7NITVYcOg74QKiwi57gzRJgKOYt1KhXMLA5y4V+xo2zBZuTzGAqNS2rHcfwil9lcsmsTOQL7felWv2C2qqUllUo3CqTGNlXo3A24guP25tr3vDm2IrH7V/TLSjJcDAI1JUi35wwrCErgxrwK9eG0Y4w=--97QWVDZ45R2Bjr3G--byi/t6soITzi5vJv5PEsvw== |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,4 +3,9 @@ | |
|
|
||
| # Defines the root path route ("/") | ||
| # root "articles#index" | ||
| namespace :api do | ||
| namespace :v1 do | ||
| post "simulate_all_plan", to: "power_supply_plan#simulate_all" | ||
|
||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| class CreateBasicCharges < ActiveRecord::Migration[7.0] | ||
| def change | ||
| create_table :providers do |t| | ||
| t.string :provider_name, :null => false | ||
| t.string :rounding_amount_method, :null => false | ||
|
|
||
| t.timestamps | ||
| end | ||
|
|
||
| create_table :power_supply_plans do |t| | ||
| t.belongs_to :provider | ||
| t.string :plan_name, :null => false | ||
|
|
||
| t.timestamps | ||
| end | ||
|
|
||
| create_table :meter_rate_charges do |t| | ||
| t.belongs_to :power_supply_plan | ||
| t.integer :min_meter_rate, :null => false | ||
| t.integer :max_meter_rate | ||
| t.decimal :price, precision: 6, scale: 2, :null => false | ||
|
|
||
| t.timestamps | ||
| end | ||
|
|
||
| create_table :basic_charges do |t| | ||
| t.belongs_to :power_supply_plan | ||
| t.integer :amp, :null => false | ||
| t.decimal :price, precision: 6, scale: 2, :null => false | ||
|
|
||
| t.timestamps | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| class RemoveRoundingAmountMethodFromProvider < ActiveRecord::Migration[7.0] | ||
| def up | ||
| remove_column :providers, :rounding_amount_method, :string | ||
| end | ||
|
|
||
| def down | ||
| add_column :providers, :rounding_amount_method, :string | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class RenameProviderNameColumnToName < ActiveRecord::Migration[7.0] | ||
| def change | ||
| rename_column :providers, :provider_name, :name | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class RenamePlanNameColumnToName < ActiveRecord::Migration[7.0] | ||
| def change | ||
| rename_column :power_supply_plans, :plan_name, :name | ||
| end | ||
| end |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
全体的に、コントローラーにすべての責務が集中してしまっている印象を受けました。
具体的には、以下のような処理がすべて controller に記述されているため、保守性や可読性の観点から、責務ごとに適切に分離した方が良いと考えています。
現時点で大きく実装を変更するのは大変かと思いますので、「今後リファクタリングする場合に、どのように責務を分けて実装するべきか」について、テキストベースで構いませんので、考えを共有いただけると嬉しいです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
コントローラの処理を最小限にし、処理を分離いたしました。db2b5d6