Omise Schedule APIを使ってみる

OmiseのSchedule APIの使い方について、ざっくり見てみようと思います。

個人的に`curl`をいちいち作ったり覚えたりするのが面倒くさいので、下記のスクリプトを使用しています:
https://github.com/keitaroemotion/omi

なので、`omi`というやつが下記の記事にちょこちょこ出てきますが、そいつがビルドした`curl`コマンドもきちんと書いてあるので、`omi`いらない人はそこだけ見てもらっても大丈夫です。

まず、Schedule APIってどんなのあるんだろうってざっと見てみると、

```
$ omi schedule
```
```
omi [schedule] list           ... list_all_schedules
omi [schedules]               ... list_all_schedules
omi [schedule] create_daily   ... charge with days interval
omi [schedule] create_monthly   ... charge with months interval
omi [schedule] create_weekly  ... charge with weekly interval (ex. Mon, Wed)
omi [schedule] create_zig_zag ... charge with inconsistent day per month
[option: -d dry_run]
[option: -e allows editing the command before execution]
[option: -v allows viewing the execution result]
[option: -l swaps URL into localhost]
[option: count counts the number of result records]
[option: --rich enables rich output]
```

- list ... 一覧表示
- create_daily ... 日毎の課金
- create_weekly ... 週毎の課金（曜日毎の課金）
- create_monthly ... 月ごとの課金
- create_zig_zag ... 月ごとに課金日が違う課金

とかがあります。

# 日毎の課金

二日おきに100円課金したい場合、以下のようにやります

```
$ omi schedule create_daily -e -v amount=100 every=2 
```

```
curl -s https://api.omise.co/schedules \
  -X POST \
  -u skey_test_58blr9gmoomin3brx21y6: \
  -d "every=2" \
  -d "period=day" \
  -d "start_date=2018-02-27" \
  -d "end_date=2118-02-03" \
  -d "charge[customer]=cust_test_5b1t0dd4cpjh32e70ty" \
  -d "charge[card]=card_test_5b1t0hjbw1g9xq7m5r1" \
  -d "charge[amount]=100" \
  -d "charge[description]=Membership fee"
```


個々のパラメータは以下の意味です。

- every      ... 間隔（日毎、週毎、月毎...)
- period     ... 間隔の単位（日、週、月）
- start_date ... 課金の開始日 (yyyy-MM-dd)
- end_date   ... 課金の終了日 (yyyy-MM-dd)
- charge[customer] ... 課金する顧客のID (`cust_...`)
- charge[card]     ... 課金する顧客のカードID(`card_...`)
- charge[amount]   ... 過金額
- charge[description] ... 備考

なので、上記のコマンドを翻訳すると、

`every=2` いつも２
`period=day` 日毎に
`start_date=2018-02-27` 2018/2/27から
`end_date=2118-02-03` 2118/2/3までの期間
`charge[customer]=cust_test_5b1t0dd4cpjh32e70ty` cust_test_5b1t0dd4cpjh32e70tyの顧客の
`charge[card]=card_test_5b1t0hjbw1g9xq7m5r1`  card_test_5b1t0hjbw1g9xq7m5r1のカードに対して
`charge[amount]=100` 100円課金するよ、

つまり2日毎に2018/2/27 - 2118/2/3までの期間、`cust_test_5b1t0dd4cpjh32e70ty`さんの`card_test_5b1t0hjbw1g9xq7m5r1`のカードに対して100円課金するということです。

結果は以下のようになります。

```
{
  "object": "schedule",
  "id": "schd_test_5b3q4mnj5nqyovnr350",
  "livemode": false,
  "location": "/schedules/schd_test_5b3q4mnj5nqyovnr350",
  "status": "active",
  "every": 2,
  "period": "day",
  "on": {
  },
  "in_words": "Every 2 day(s)",
  "start_date": "2018-02-27",
  "end_date": "2118-02-03",
  "charge": {
    "amount": 100,
    "currency": "jpy",
    "description": "Membership fee",
    "customer": "cust_test_5b1t0dd4cpjh32e70ty",
    "card": "card_test_5b1t0hjbw1g9xq7m5r1"
  },
  "occurrences": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2018-02-27T06:18:24Z",
    "offset": 0,
    "limit": 20,
    "total": 1,
    "order": null,
    "location": "/schedules/schd_test_5b3q4mnj5nqyovnr350/occurrences",
    "data": [
      {
        "object": "occurrence",
        "id": "occu_test_5b3q4mnktcyl71pm2p6",
        "livemode": false,
        "location": "/occurrences/occu_test_5b3q4mnktcyl71pm2p6",
        "schedule": "schd_test_5b3q4mnj5nqyovnr350",
        "schedule_date": "2018-02-27",
        "retry_date": null,
        "processed_at": "2018-02-27T06:18:24Z",
        "status": "successful",
        "message": null,
        "result": "chrg_test_5b3q4mojujzoty1ril9",
        "created": "2018-02-27T06:18:23Z"
      }
    ]
  },
  "next_occurrence_dates": [
    "2018-03-01",
    "2018-03-03",
    "2018-03-05",
    "2018-03-07",
    "2018-03-09",
    "2018-03-11",
    "2018-03-13",
    "2018-03-15",
    "2018-03-17",
    "2018-03-19",
    "2018-03-21",
    "2018-03-23",
    "2018-03-25",
    "2018-03-27",
    "2018-03-29",
    "2018-03-31",
    "2018-04-02",
    "2018-04-04",
    "2018-04-06",
    "2018-04-08",
    "2018-04-10",
    "2018-04-12",
    "2018-04-14",
    "2018-04-16",
    "2018-04-18",
    "2018-04-20",
    "2018-04-22",
    "2018-04-24",
    "2018-04-26",
    "2018-04-28"
  ],
  "created": "2018-02-27T06:18:23Z"
}
```

ごにょごにょ、っと書いてありますが、

```
  "next_occurrence_dates": [
    "2018-03-01",
    "2018-03-03",
    "2018-03-05",
    "2018-03-07",
    "2018-03-09",
    "2018-03-11",
    "2018-03-13",
    "2018-03-15",
    "2018-03-17",
    "2018-03-19",
    "2018-03-21",
    "2018-03-23",
    "2018-03-25",
    "2018-03-27",
    "2018-03-29",
    "2018-03-31",
    "2018-04-02",
    "2018-04-04",
    "2018-04-06",
    "2018-04-08",
    "2018-04-10",
    "2018-04-12",
    "2018-04-14",
    "2018-04-16",
    "2018-04-18",
    "2018-04-20",
    "2018-04-22",
    "2018-04-24",
    "2018-04-26",
    "2018-04-28"
  ],

```

この`next_occurence_dates`というところで次いつ課金するか、がある程度のスコープで記述されている、という感じですね。

# 曜日毎の課金

```
$ omi schedule create_weekly -e -v amount=100
```

```
curl -s https://api.omise.co/schedules \
  -X POST \
  -u skey_test_58blr9gmoomin3brx21y6: \
  -d "every=1" \
  -d "period=week" \
  -d "on[weekdays][]=monday" \
  -d "on[weekdays][]=friday" \
  -d "start_date=2018-02-27" \
  -d "end_date=2118-02-03" \
  -d "charge[customer]=cust_test_5b1t0dd4cpjh32e70ty" \
  -d "charge[amount]=100" \
  -d "charge[description]=Membership fee"
```

`every=1` 毎
`period=week` 週
`on[weekdays][]=monday` 月曜日と
`on[weekdays][]=friday` 金曜日に
`start_date=2018-02-27` 2/27から
`end_date=2118-02-03` 100年後の2/3日まで
`charge[customer]=cust_test_5b1t0dd4cpjh32e70ty` cust_test_5b1t0dd4cpjh32e70tyさんに
`charge[amount]=100` 100円課金する

つまり、毎週月金で2/27-100年後の2/3まで、`cust_test_5b1t0dd4cpjh32e70ty`さんに（カードは指定してないのでデフォルトカードで）100円課金する

ということになります。結果は、

```
{
  "object": "schedule",
  "id": "schd_test_5b3qa9jvwh51rdlag09",
  "livemode": false,
  "location": "/schedules/schd_test_5b3qa9jvwh51rdlag09",
  "status": "active",
  "every": 1,
  "period": "week",
  "on": {
    "weekdays": [
      "monday",
      "friday"
    ]
  },
  "in_words": "Every 1 week(s) on Monday and Friday",
  "start_date": "2018-02-27",
  "end_date": "2118-02-03",
  "charge": {
    "amount": 100,
    "currency": "jpy",
    "description": "Membership fee",
    "customer": "cust_test_5b1t0dd4cpjh32e70ty",
    "card": null
  },
  "occurrences": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2018-02-27T06:34:24Z",
    "offset": 0,
    "limit": 20,
    "total": 0,
    "order": null,
    "location": "/schedules/schd_test_5b3qa9jvwh51rdlag09/occurrences",
    "data": [

    ]
  },
  "next_occurrence_dates": [
    "2018-03-02",
    "2018-03-05",
    "2018-03-09",
    "2018-03-12",
    "2018-03-16",
    "2018-03-19",
    "2018-03-23",
    "2018-03-26",
    "2018-03-30",
    "2018-04-02",
    "2018-04-06",
    "2018-04-09",
    "2018-04-13",
    "2018-04-16",
    "2018-04-20",
    "2018-04-23",
    "2018-04-27",
    "2018-04-30",
    "2018-05-04",
    "2018-05-07",
    "2018-05-11",
    "2018-05-14",
    "2018-05-18",
    "2018-05-21",
    "2018-05-25",
    "2018-05-28",
    "2018-06-01",
    "2018-06-04",
    "2018-06-08",
    "2018-06-11"
  ],
  "created": "2018-02-27T06:34:24Z"
}
```

また、週一回なら、

```
curl -s https://api.omise.co/schedules \
  -X POST \
  -u skey_test_58blr9gmoomin3brx21y6: \
  -d "every=1" \
  -d "period=week" \
  -d "on[weekdays][]=monday" \
  -d "start_date=2018-02-27" \
  -d "end_date=2118-02-03" \
  -d "charge[customer]=cust_test_5b1t0dd4cpjh32e70ty" \
  -d "charge[amount]=100" \
  -d "charge[description]=Membership fee"
```


# 月毎の課金

```
omi schedule create_monthly -e -v amount=100 day=25
```
```
curl -s https://api.omise.co/schedules \
    -X POST \
    -u skey_test_58blr9gmoomin3brx21y6: \
    -d "every=1" \
    -d "period=month" \
    -d "on[days_of_month][]=25" \
    -d "start_date=2018-02-27" \
    -d "end_date=2118-02-03" \
    -d "charge[customer]=cust_test_5b1t0dd4cpjh32e70ty" \
    -d "charge[amount]=100" \
    -d "charge[description]=Membership fee"
```

`on[days_of_month][]=25`のところで、毎月何日に課金するかが設定されています。

```
  "object": "schedule",
  "id": "schd_test_5b3qd0o3vj6k86h4w8k",
  "livemode": false,
  "location": "/schedules/schd_test_5b3qd0o3vj6k86h4w8k",
  "status": "active",
  "every": 1,
  "period": "month",
  "on": {
    "days_of_month": [
      25
    ]
  },
  "in_words": "Every 1 month(s) on the 25th",
  "start_date": "2018-02-27",
  "end_date": "2118-02-03",
  "charge": {
    "amount": 100,
    "currency": "jpy",
    "description": "Membership fee",
    "customer": "cust_test_5b1t0dd4cpjh32e70ty",
    "card": null
  },
  "occurrences": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2018-02-27T06:42:14Z",
    "offset": 0,
    "limit": 20,
    "total": 0,
    "order": null,
    "location": "/schedules/schd_test_5b3qd0o3vj6k86h4w8k/occurrences",
    "data": [

    ]
  },
  "next_occurrence_dates": [
    "2018-03-25",
    "2018-04-25",
    "2018-05-25",
    "2018-06-25",
    "2018-07-25",
    "2018-08-25",
    "2018-09-25",
    "2018-10-25",
    "2018-11-25",
    "2018-12-25",
    "2019-01-25",
    "2019-02-25",
    "2019-03-25",
    "2019-04-25",
    "2019-05-25",
    "2019-06-25",
    "2019-07-25",
    "2019-08-25",
    "2019-09-25",
    "2019-10-25",
    "2019-11-25",
    "2019-12-25",
    "2020-01-25",
    "2020-02-25",
    "2020-03-25",
    "2020-04-25",
    "2020-05-25",
    "2020-06-25",
    "2020-07-25",
    "2020-08-25"
  ],
  "created": "2018-02-27T06:42:13Z"
}
```

# 月単位で、一月に複数回の課金

```
omi schedule create_zig_zag -e -v amount=100
```
この場合、 everyの値(3) と、 `on[days_of_month][]`の個数が一致していることがポイントとなります。このため、月ごとで課金日が `1, 10, 15日`となり、これをループしていく形となります。

```
curl -s https://api.omise.co/schedules \
    -X POST \
    -u skey_test_58blr9gmoomin3brx21y6: \
    -d "every=3" \
    -d "period=month" \
    -d "on[days_of_month][]=1" \
    -d "on[days_of_month][]=10" \
    -d "on[days_of_month][]=15" \
    -d "start_date=2018-02-27" \
    -d "end_date=2118-02-03" \
    -d "charge[customer]=cust_test_5b1t0dd4cpjh32e70ty" \
    -d "charge[amount]=100" \
    -d "charge[description]=Membership fee"
```

結果は以下のようになります。

```
{
  "object": "schedule",
  "id": "schd_test_5b3qe5yemv2bhxwp4y2",
  "livemode": false,
  "location": "/schedules/schd_test_5b3qe5yemv2bhxwp4y2",
  "status": "active",
  "every": 3,
  "period": "month",
  "on": {
    "days_of_month": [
      1,
      10,
      15
    ]
  },
  "in_words": "Every 3 month(s) on the 1st, 10th, and 15th",
  "start_date": "2018-02-27",
  "end_date": "2118-02-03",
  "charge": {
    "amount": 100,
    "currency": "jpy",
    "description": "Membership fee",
    "customer": "cust_test_5b1t0dd4cpjh32e70ty",
    "card": null
  },
  "occurrences": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2018-02-27T06:45:29Z",
    "offset": 0,
    "limit": 20,
    "total": 0,
    "order": null,
    "location": "/schedules/schd_test_5b3qe5yemv2bhxwp4y2/occurrences",
    "data": [

    ]
  },
  "next_occurrence_dates": [
    "2018-03-01",
    "2018-03-10",
    "2018-03-15",
    "2018-06-01",
    "2018-06-10",
    "2018-06-15",
    "2018-09-01",
    "2018-09-10",
    "2018-09-15",
    "2018-12-01",
    "2018-12-10",
    "2018-12-15",
    "2019-03-01",
    "2019-03-10",
    "2019-03-15",
    "2019-06-01",
    "2019-06-10",
    "2019-06-15",
    "2019-09-01",
    "2019-09-10",
    "2019-09-15",
    "2019-12-01",
    "2019-12-10",
    "2019-12-15",
    "2020-03-01",
    "2020-03-10",
    "2020-03-15",
    "2020-06-01",
    "2020-06-10",
    "2020-06-15"
  ],
  "created": "2018-02-27T06:45:29Z"
}
```

# 定期課金一覧の取得

```
$ omi schedules
```
```
curl -s -X GET https://api.omise.co/schedules \
  -u skey_test_58blr9gmoomin3brx21y6:
```
# 定期課金の削除（無効化）
厳密にはレコード自体を削除はできないんですが、`status: deleted`にして事実上削除した状態にできます。

```
$ omi schedule delete
```

```
curl -s https://api.omise.co/schedules/schd_test_5b3qduov0jfe5i2rycs \
  -X DELETE \
  -u skey_test_58blr9gmoomin3brx21y6:

{
  "object": "schedule",
  "id": "schd_test_5b3qduov0jfe5i2rycs",
  "livemode": false,
  "location": "/schedules/schd_test_5b3qduov0jfe5i2rycs",
  "status": "deleted",
  "every": 3,
  "period": "month",
  "on": {
    "days_of_month": [
      1,
      10,
      15
    ]
  },
  "in_words": "Every 3 month(s) on the 1st, 10th, and 15th",
  "start_date": "2019-05-01",
  "end_date": "2089-05-01",
  "charge": {
    "amount": 100,
    "currency": "jpy",
    "description": "Membership fee",
    "customer": "cust_test_5b1t0dd4cpjh32e70ty",
    "card": null
  },
  "occurrences": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2018-02-27T07:04:20Z",
    "offset": 0,
    "limit": 20,
    "total": 0,
    "order": null,
    "location": "/schedules/schd_test_5b3qduov0jfe5i2rycs/occurrences",
    "data": [

    ]
  },
  "next_occurrence_dates": [

  ],
  "created": "2018-02-27T06:44:35Z"
}
```
# 日割り計算とかしたい場合

日割り計算をしたい場合、顧客のアカウント登録時からその月の最後までの計算、チャージの計算、その後でのスケジュール作成などは自分で実装することになります。以下のような感じで実装します。[ソースはこちらから入手可能です](https://github.com/keitaroemotion/omi/blob/master/scripts/utility/hiwari)

```
#!/usr/bin/env ruby

#      March 2018       
# Su Mo Tu We Th Fr Sa  
#              1  2  3  
#  4  5  6  7  8  9 10  
# 11 12 13 14[15]16 17  
# 18 19 20 21 22 23 24  
# 25 26 27 28 29 30 31  
#
# This means the days_remained is 17.
# Supposed that the customer is going to be charged with
# 2000 yen...
#
# FOR THE INTENSION TO MAKE IT RECOGNIZABLE TO
# JAPANESE DEVELOPERS, THE TERM "HIWARI" IS USED
# WHICH MEANS CHARGE PER DAY.
#

require 'date'

class Test
  def self.assert(expected, real)
    if expected != real
      abort("expected: #{expected}, real: #{real}")
    end
  end
end  

class User
  #
  # intentionally refrains from using attr_reader
  # so that the structure is easy to be grasped for now
  # 
  def initialize(sign_in_date:, charge_amount:, customer_id:)
    @sign_in_date          = sign_in_date
    @charge_amount         = charge_amount
    @customer_id           = customer_id
    @stupidly_large_number = 10000                                            
  end

  def sign_in_date
    @sign_in_date
  end

  def charge_amount
    @charge_amount
  end

  def customer_id
    @customer_id
  end

  def scheduled_charge_start_date
    Date.new(@sign_in_date.year, @sign_in_date.month + 1, 1)
  end  

  def scheduled_charge_end_date
    scheduled_charge_start_date + @stupidly_large_number
  end  

  def days_remained
    Date.new(sign_in_date.year, sign_in_date.month, -1).day - sign_in_date.day + 1
  end

  def hiwari_amount_total
    days_remained * charge_amount
  end
end

def charge(skey, hiwari_amount_total, user)
  "curl -s https://api.omise.co/charges \\\n" \
  "  -X POST \\\n" \
  "  -u #{skey}: \\\n" \
  "  -d \"amount=#{hiwari_amount_total}\" \\\n" \
  "  -d \"currency=jpy\" \\\n" \
  "  -d \"customer=#{user.customer_id}\""
end

def create_schedule(skey, user, day)
  "curl -s https://api.omise.co/schedules\\\n" \
  "  -X POST \\\n" \
  "  -u #{skey}: \\\n" \
  "  -d \"every=1\" \\\n" \
  "  -d \"period=month\" \\\n" \
  "  -d \"on[days_of_month][]=#{day}\" \\\n" \
  "  -d \"start_date=#{user.scheduled_charge_start_date}\" \\\n" \
  "  -d \"end_date=#{user.scheduled_charge_end_date}\" \\\n" \
  "  -d \"charge[customer]=#{user.customer_id}\" \\\n" \
  "  -d \"charge[amount]=#{user.charge_amount}\" \\\n" \
  "  -d \"charge[description]=Membership fee\""
end

skey = ARGV[0]


#
# Case 1: signin_date: 2018/3/15
#

user = User.new(
         sign_in_date:  Date.new(2018, 3, 15),
         charge_amount: 2000,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert 17, user.days_remained
Test.assert 34000, user.hiwari_amount_total
puts charge(skey, user.hiwari_amount_total, user)
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")

#
# Case 2: signin_date: 2018/3/1
#

user = User.new(
         sign_in_date:  Date.new(2018, 3, 1),
         charge_amount: 100,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert 31,   user.days_remained
Test.assert 3100, user.hiwari_amount_total
puts charge(skey, user.hiwari_amount_total, user)
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")

#
# Case 3: signin_date: 2018/3/31
#

user = User.new(
         sign_in_date:  Date.new(2018, 3, 31),
         charge_amount: 100,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert 1,    user.days_remained
Test.assert 100,  user.hiwari_amount_total
puts charge(skey, user.hiwari_amount_total, user)
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")
```

# 初月無料とかしたい場合

初月無料にしたい場合は、**顧客の登録の月 + 1**からスケジュール課金を始めればいいので、以下のようになります。[ソースはこちら](https://github.com/keitaroemotion/omi/blob/master/scripts/utility/init_free)

```
#!/usr/bin/env ruby

#      March 2018       
# Su Mo Tu We Th Fr Sa  
#              1  2  3  
#  4  5  6  7  8  9 10  
# 11 12 13 14[15]16 17  
# 18 19 20 21 22 23 24  
# 25 26 27 28 29 30 31  
#

require 'date'

class Test
  def self.assert(expected, real)
    if expected != real
      abort("expected: #{expected}, real: #{real}")
    end
  end
end  

class User
  #
  # intentionally refrains from using attr_reader
  # so that the structure is easy to be grasped for now
  # 
  def initialize(sign_in_date:, charge_amount:, customer_id:)
    @sign_in_date          = sign_in_date
    @charge_amount         = charge_amount
    @customer_id           = customer_id
    @stupidly_large_number = 10000                                            
  end

  def sign_in_date
    @sign_in_date
  end

  def charge_amount
    @charge_amount
  end

  def customer_id
    @customer_id
  end

  def scheduled_charge_start_date
    Date.new(@sign_in_date.year, @sign_in_date.month + 1, 1)
  end  

  def scheduled_charge_end_date
    scheduled_charge_start_date + @stupidly_large_number
  end  
end

def create_schedule(skey, user, day)
  "curl -s https://api.omise.co/schedules\\\n" \
  "  -X POST \\\n" \
  "  -u #{skey}: \\\n" \
  "  -d \"every=1\" \\\n" \
  "  -d \"period=month\" \\\n" \
  "  -d \"on[days_of_month][]=#{day}\" \\\n" \
  "  -d \"start_date=#{user.scheduled_charge_start_date}\" \\\n" \
  "  -d \"end_date=#{user.scheduled_charge_end_date}\" \\\n" \
  "  -d \"charge[customer]=#{user.customer_id}\" \\\n" \
  "  -d \"charge[amount]=#{user.charge_amount}\" \\\n" \
  "  -d \"charge[description]=Membership fee\""
end

skey = ARGV[0]

#
# Case 1: signin_date: 2018/3/15
#         then, the charge starts from 2018/4/1
#
user = User.new(
         sign_in_date:  Date.new(2018, 3, 15),
         charge_amount: 2000,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")

#
# Case 2: signin_date: 2018/3/1
#         then, the charge starts from 2018/4/1
#
user = User.new(
         sign_in_date:  Date.new(2018, 3, 1),
         charge_amount: 2000,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")

#
# Case 3: signin_date: 2018/3/31
#         then, the charge starts from 2018/4/1
#
user = User.new(
         sign_in_date:  Date.new(2018, 3, 31),
         charge_amount: 2000,
         customer_id:   "cust_test_5b4vkgkeal49aafdo2k"
       )
Test.assert "2018-04-01", user.scheduled_charge_start_date.to_s
Test.assert "2045-08-17", user.scheduled_charge_end_date.to_s
puts create_schedule(skey, user, "25")
```

# 定期課金(Schedule)の更新
更新はできません。削除のうえ、新規に作成する必要があります


などなどです。質問はコメントからお願いします