Edited at

Omise Schedule APIを使ってみる

More than 1 year has passed since last update.

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 いつも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"
}


日割り計算とかしたい場合

日割り計算をしたい場合、顧客のアカウント登録時からその月の最後までの計算、チャージの計算、その後でのスケジュール作成などは自分で実装することになります。以下のような感じで実装します。ソースはこちらから入手可能です

#!/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からスケジュール課金を始めればいいので、以下のようになります。ソースはこちら

#!/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)の更新

更新はできません。削除のうえ、新規に作成する必要があります

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