今天要介紹的是 LINE Pay,這是 LINE 推出的行動支付服務,聽說可以用來繳水費和電費等帳單,今天就來看看如何使用 LINE Pay 製作行動支付機器人。
LINE Pay 的付款方式很多,這邊我挑 「一般付款」 來作範例。
主要分為兩大步驟「Reserve」和「Confirm」。
POST /v2/payments/request
POST /v2/payments/{transactionId}/confirm
範例只是讓大家了解流程,實務上作法很多,建議直接看 官方文件。
https://pay.line.me/jp/developers/main/main?locale=zh_TW
var flexMessage = new FlexMessage("購物車")
{
Contents = new BubbleContainer
{
Body = new BoxComponent
{
Layout = BoxLayout.Vertical,
Contents = new List<IFlexComponent>
{
new TextComponent
{
Text = "購物車",
Weight = Weight.Bold,
Size = ComponentSize.Xxl,
Margin = Spacing.Md
},
new SeparatorComponent
{
Margin = Spacing.Xxl
},
new BoxComponent
{
Layout = BoxLayout.Vertical,
Margin = Spacing.Xxl,
Spacing = Spacing.Sm,
Contents = new List<IFlexComponent>
{
new BoxComponent
{
Layout = BoxLayout.Horizontal,
Contents = new List<IFlexComponent>
{
new TextComponent
{
Text= "波霸紅茶拿鐵",
Size = ComponentSize.Sm,
Flex = 0,
Weight = Weight.Bold
},
new TextComponent
{
Text= "NT$60",
Size = ComponentSize.Sm,
Align = Align.End,
Weight = Weight.Bold
}
}
},
new BoxComponent
{
Layout = BoxLayout.Horizontal,
Contents = new List<IFlexComponent>
{
new TextComponent
{
Text= "四季春春青茶",
Size = ComponentSize.Sm,
Flex = 0,
Weight = Weight.Bold
},
new TextComponent
{
Text= "NT$30",
Size = ComponentSize.Sm,
Align = Align.End,
Weight = Weight.Bold
}
}
}
}
},
new SeparatorComponent
{
Margin = Spacing.Xxl
},
new BoxComponent
{
Layout = BoxLayout.Horizontal,
Margin = Spacing.Md,
Contents = new List<IFlexComponent>
{
new TextComponent
{
Text= "總金額",
Size = ComponentSize.Sm,
Flex = 0,
Weight = Weight.Bold
},
new TextComponent
{
Text= "NT$90",
Size = ComponentSize.Sm,
Align = Align.End,
Weight = Weight.Bold
}
}
},
new SeparatorComponent
{
Margin = Spacing.Md
}
}
},
Footer = new BoxComponent
{
Layout = BoxLayout.Vertical,
Contents = new List<IFlexComponent>
{
new ButtonComponent
{
Style = ButtonStyle.Primary,
Action = new PostbackTemplateAction("結帳", "結帳")
}
}
}
}
};
await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
new List<ISendMessage> { flexMessage });
protected override async Task OnPostbackAsync(PostbackEvent ev)
{
if (ev.Postback.Data == "結帳")
{
dynamic dy = null as dynamic;
//呼叫 API 授權付款
using (var httpClient = new HttpClient())
{
//設定 Header
httpClient.DefaultRequestHeaders
.Add("X-LINE-ChannelId", "123456789");
httpClient.DefaultRequestHeaders
.Add("X-LINE-ChannelSecret", "abcde12345");
//設定 Body
var body = new
{
amount = 90,
productName = "iBot",
productImageUrl = "https://xxxxx/image.png",
confirmUrl = "https://xxxxx/api/linebot/pay/confirm",
//訂單編號,不能重複
orderId = Guid.NewGuid().ToString(),
currency = "TWD"
};
var content = new StringContent(JsonConvert.SerializeObject(body),
Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(
"https://sandbox-api-pay.line.me/v2/payments/request", content);
var result = await response.Content.ReadAsStringAsync();
dy = JObject.Parse(result);
}
//新增訂單
var order = new Order
{
UserId = ev.Source.UserId,
Amount = 90,
Status = "未付款",
OrderId = Guid.NewGuid().ToString(),
TransactionId = dy.info.transactionId
};
_db.Orders.Add(order);
await _db.SaveChangesAsync();
//回覆付款連結
var flexMessage = new FlexMessage("付款")
{
Contents = new BubbleContainer
{
Body = new BoxComponent
{
Layout = BoxLayout.Vertical,
Contents = new List<IFlexComponent>
{
new TextComponent
{
Text = "使用 LINE Pay 付款",
Weight = Weight.Bold,
Size = ComponentSize.Md,
Align = Align.Center
}
}
},
Footer = new BoxComponent
{
Layout = BoxLayout.Vertical,
Contents = new List<IFlexComponent>
{
new ButtonComponent
{
Action = new UriTemplateAction("Pay NT$90",
$"line://app/123456789-OXOXOXOX?url={dy.info.paymentUrl.web}")
}
}
},
Styles = new BubbleStyles
{
Footer = new BlockStyle
{
Separator = true
}
}
}
};
await _messagingClient.ReplyMessageAsync(ev.ReplyToken,
new List<ISendMessage> { flexMessage });
}
}
@page
@model iBotTest.LIFFModel
@{
Layout = null;
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iBot</title>
</head>
<body>
<script>
//轉址到付款頁面
var url = new URL(location.href);
location.href = url.searchParams.get("url");
</script>
</body>
</html>
[HttpGet("pay/confirm")]
public async Task<string> PayConfirm([FromQuery]string transactionId)
{
var lineMessagingClient =
new LineMessagingClient(_lineBotConfig.accessToken);
var order = await _db.Orders
.Where(it => it.TransactionId == transactionId)
.FirstOrDefaultAsync();
dynamic dy = null as dynamic;
//呼叫 API 確認付款
using (var httpClient = new HttpClient())
{
//設定 Header
httpClient.DefaultRequestHeaders
.Add("X-LINE-ChannelId", "123456789");
httpClient.DefaultRequestHeaders
.Add("X-LINE-ChannelSecret", "abcde12345");
//設定 Body
var body = new
{
amount = 90,
currency = "TWD"
};
var content = new StringContent(JsonConvert.SerializeObject(body),
Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(
$"https://sandbox-api-pay.line.me/v2/payments/{transactionId}/confirm", content);
var result = await response.Content.ReadAsStringAsync();
dy = JObject.Parse(result);
}
//更新付款狀態
order.Status = "已付款";
await _db.SaveChangesAsync();
//回覆結果
if (dy.returnCode == "0000")
await lineMessagingClient.PushMessageAsync(order.UserId, "付款完成!!");
else
await lineMessagingClient.PushMessageAsync(order.UserId, "付款失敗!!");
return "付款完成!!";
}
字好小,這裡使用 Razor Page 會比較好。
下一篇要介紹 Account Link,今天就到這裡,感謝大家觀看。 (´・ω・`)
本文為教學用途,程式省略很多細節,不能直接用在實務上。
[30 天教你如何玩弄 Line bot API] 第 23 天:來購物啊!- LINE Pay API
Day 06 - Linepay (4) 付款 reserve API
這大概是我看過最最清楚的講解了,謝謝您的教學!
謝謝!!
因為台灣的教學,都只有一部分,只有串的那部份,沒有教人家怎麼寫畫面,當然....因為我太菜了....