Skip to content
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

決済が後から確定する種別への対応 #2

Merged
merged 6 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"dockerComposeFile": ["../docker-compose.yml"],
"service": "web",
"workspaceFolder": "/var/lib/nginx/html/app/Plugin/UnivaPay",
"customizations": {
"vscode": {
"settings": {
"php.validate.enable": false,
"php.suggest.basic": false,
"[php]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client"
}
},
"extensions": [
"bmewburn.vscode-intelephense-client",
"ms-azuretools.vscode-docker"
]
}
}
}
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: cd UnivaPay && tar -cvzf UnivaPay.tar.gz *
run: tar -cvzf UnivaPay.tar.gz *
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
UnivaPay/UnivaPay.tar.gz
UnivaPay.tar.gz
Empty file modified .gitignore
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function index(Request $request)
*/
public function sdk(Request $request) {
try {
$log = $this->composerService->execRequire('univapay/php-sdk:6.2.1');
$log = $this->composerService->execRequire('univapay/php-sdk:6.5.0');
return $this->redirectToRoute('univa_pay_admin_config', ['error' => 0]);
} catch (Exception $e) {
return $this->redirectToRoute('univa_pay_admin_config', ['error' => 1]);
Expand Down
292 changes: 292 additions & 0 deletions Controller/SubscriptionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
<?php
namespace Plugin\UnivaPay\Controller;

use Eccube\Controller\AbstractController;
use Eccube\Entity\Master\OrderStatus;
use Eccube\Entity\Order;
use Eccube\Repository\Master\OrderStatusRepository;
use Eccube\Repository\OrderRepository;
use Eccube\Service\MailService;
use Eccube\Service\OrderHelper;
use Eccube\Service\PurchaseFlow\Processor\AddPointProcessor;
use Eccube\Service\PurchaseFlow\Processor\OrderNoProcessor;
use Eccube\Service\PurchaseFlow\PurchaseContext;
use Eccube\Service\PurchaseFlow\PurchaseFlow;
use Plugin\UnivaPay\Repository\ConfigRepository;
use Plugin\UnivaPay\Util\SDK;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class SubscriptionController extends AbstractController
{
/** @var ConfigRepository */
protected $Config;

/** @var OrderRepository */
protected $Order;

/**
* @var OrderStatusRepository
*/
private $orderStatusRepository;

/**
* @var PurchaseFlow
*/
private $purchaseFlow;

/**
* @var OrderHelper
*/
private $orderHelper;

/**
* @var MailService
*/
protected $mailService;

/**
* OrderController constructor.
*
* @param ConfigRepository $configRepository
* @param OrderRepository $orderRepository
* @param OrderStatusRepository $orderStatusRepository
* @param PurchaseFlow $shoppingPurchaseFlow
* @param OrderHelper $orderHelper
* @param OrderNoProcessor $orderNoProcessor
* @param AddPointProcessor $addPointProcessor
* @param MailService $mailService
*/
public function __construct(
ConfigRepository $configRepository,
OrderRepository $orderRepository,
OrderStatusRepository $orderStatusRepository,
PurchaseFlow $shoppingPurchaseFlow,
OrderHelper $orderHelper,
OrderNoProcessor $orderNoProcessor,
AddPointProcessor $addPointProcessor,
MailService $mailService
) {
$this->Config = $configRepository;
$this->Order = $orderRepository;
$this->orderStatusRepository = $orderStatusRepository;
$this->purchaseFlow = $shoppingPurchaseFlow;
$this->orderHelper = $orderHelper;
$this->orderNoProcessor = $orderNoProcessor;
$this->addPointProcessor = $addPointProcessor;
$this->mailService = $mailService;
}

/**
* subscription webhook action
*
* @Method("POST")
* @Route("/univapay/hook", name="univa_pay_hook")
*/
public function hook(Request $request)
{
$data = json_decode($request->getContent());
$existOrder = $this->Order->findOneBy(["order_no" => $data->data->metadata->orderNo]);
if (is_null($existOrder))
return new Response();

$config = $this->Config->findOneById(1);
$util = new SDK($config);
$charge = null;
if ($data->event === 'subscription_payment' || $data->event === 'subscription_failure') {
// SubscriptionIdからChargeを取得
$charge = $util->getChargeBySubscriptionId($data->data->id);
} elseif ( $data->event === 'charge_finished') {
// 支払い確定したら注文ステータスを変更する
// セキュリティのために一様UUIDを確認する
if ($data->data->id !== $existOrder->getUnivapayChargeId())
return new Response();
$OrderStatus = $this->orderStatusRepository->find(OrderStatus::PAID);
$existOrder->setOrderStatus($OrderStatus);
$existOrder->setPaymentDate(new \DateTime());
$this->entityManager->persist($existOrder);
$this->entityManager->flush();
return new Response();
}
if (is_null($charge))
return new Response();
// 再課金待ちもしくは初回課金の場合は何もしない
if ($data->data->status === 'unpaid' || $charge->id === $existOrder->getUnivapayChargeId())
return new Response();
// cloneで注文を複製してもidが変更できないため一から作成
$newOrder = new Order;
// 今回での決済の課金ID取得
$newOrder->setUnivapayChargeId($charge->id);
$newOrder->setUnivapaySubscriptionId($existOrder->getUnivapaySubscriptionId());
$newOrder->setMessage($existOrder->getMessage());
$newOrder->setName01($existOrder->getName01());
$newOrder->setName02($existOrder->getName02());
$newOrder->setKana01($existOrder->getKana01());
$newOrder->setKana02($existOrder->getKana02());
$newOrder->setCompanyName($existOrder->getCompanyName());
$newOrder->setEmail($existOrder->getEmail());
$newOrder->setPhoneNumber($existOrder->getPhoneNumber());
$newOrder->setPostalCode($existOrder->getPostalCode());
$newOrder->setAddr01($existOrder->getAddr01());
$newOrder->setAddr02($existOrder->getAddr02());
$newOrder->setBirth($existOrder->getBirth());
// 今回決済金額から小計を逆算
$newSubtotal = $existOrder->getSubtotal() - $existOrder->getTotal() + $data->data->amount - $existOrder->getDiscount();
$newOrder->setSubtotal($newSubtotal);
// 割引無効化
$newOrder->setDiscount(0);
$newOrder->setDeliveryFeeTotal($existOrder->getDeliveryFeeTotal());
$newOrder->setCharge($existOrder->getCharge());
$newOrder->setTax($existOrder->getTax());
// 二回目以降の決済金額が違う場合があるため変更
$newOrder->setTotal($data->data->amount);
$newOrder->setPaymentTotal($data->data->amount);
$newOrder->setPaymentMethod($existOrder->getPaymentMethod());
$newOrder->setNote($existOrder->getNote());
$newOrder->setCurrencyCode($existOrder->getCurrencyCode());
$newOrder->setCompleteMessage($existOrder->getCompleteMessage());
$newOrder->setCompleteMailMessage($existOrder->getCompleteMailMessage());
// 決済日を今日に変更
$newOrder->setPaymentDate(new \DateTime());
$newOrder->setCustomer($existOrder->getCustomer());
$newOrder->setCountry($existOrder->getCountry());
$newOrder->setPref($existOrder->getPref());
$newOrder->setSex($existOrder->getSex());
$newOrder->setJob($existOrder->getJob());
$newOrder->setPayment($existOrder->getPayment());
$newOrder->setDeviceType($existOrder->getDeviceType());
$newOrder->setCustomerOrderStatus($existOrder->getCustomerOrderStatus());
$newOrder->setOrderStatusColor($existOrder->getOrderStatusColor());
// 商品ごとの今回課金金額を取得
$amount = json_decode($existOrder->getUnivapayChargeAmount());
// 商品金額が存在しなかったらその時点のデータを作成する
if(!$amount) {
$items = [];
foreach($existOrder->getOrderItems() as $value) {
// 商品単位で金額を取得
if($value->isProduct()) {
$class = $value->getProductClass();
$items[$class->getId()] = ['price' => $class->getPrice01(), 'tax' => $class->getPrice01IncTax() - $class->getPrice01()];
}
}
$newOrder->setUnivapayChargeAmount(json_encode($items));
$amount = json_decode($newOrder->getUnivapayChargeAmount());
}
$amount = get_object_vars($amount);
foreach($existOrder->getOrderItems() as $value) {
$newOrderItem = clone $value;
// 値引きは引き継がない
if($newOrderItem->isDiscount() || $newOrderItem->isPoint())
continue;
// OrderItemごとの金額を修正する
if($newOrderItem->isProduct()) {
// 二回目は通常金額を取得する
$class = $newOrderItem->getProductClass();
$newOrderItem->setPrice($amount[$class->getId()]->price);
$newOrderItem->setTax($amount[$class->getId()]->tax);
}
$newOrderItem->setOrder($newOrder);
$newOrder->addOrderItem($newOrderItem);
}
foreach($existOrder->getShippings() as $value) {
$newShipping = clone $value;
$newShipping->setShippingDeliveryDate(NULL);
$newShipping->setShippingDeliveryTime(NULL);
$newShipping->setTimeId(NULL);
$newShipping->setShippingDate(NULL);
$newShipping->setTrackingNumber(NULL);
$newShipping->setOrder($newOrder);
// 循環参照してしまい正常に発送データがセットできないため
foreach($newShipping->getOrderItems() as $v) {
$newShipping->removeOrderItem($v);
}
foreach($newOrder->getOrderItems() as $v) {
if($v->getShipping() && $v->getShipping()->getId() == $value->getId()) {
$v->setShipping($newShipping);
$newShipping->addOrderItem($v);
}
}
$newOrder->addShipping($newShipping);
}
$purchaseContext = new PurchaseContext($newOrder, $newOrder->getCustomer());
// ポイントを再計算4.0以前のバージョンの場合、先にポイントを再計算を行わないと正常に動かない
$this->addPointProcessor->validate($newOrder, $purchaseContext);
// 注文番号変更
$preOrderId = $this->orderHelper->createPreOrderId();
$newOrder->setPreOrderId($preOrderId);
// 購入処理を完了
$this->purchaseFlow->prepare($newOrder, $purchaseContext);
$this->purchaseFlow->commit($newOrder, $purchaseContext);
$this->entityManager->persist($newOrder);
// 注文番号が重複しないように再採番
$this->entityManager->flush();
$this->orderNoProcessor->process($newOrder, $purchaseContext);
$this->entityManager->flush();
// 定期課金に失敗した場合はキャンセル済み注文に変更
$OrderStatus = $this->orderStatusRepository->find($data->data->status === 'suspended' ? OrderStatus::CANCEL : OrderStatus::PAID);
$newOrder->setOrderStatus($OrderStatus);
if($config->getMail())
$this->mailService->sendOrderMail($newOrder);
$this->entityManager->flush();
return new Response();
}

/**
* subscription cancel action
*
* @Method("POST")
* @Route("/univapay/subscription/cancel/{id}", requirements={"id" = "\d+"}, name="univa_pay_cancel_subscription")
*/
public function cancelSubscription(Request $request, Order $Order)
{
if ($request->isXmlHttpRequest() && $this->isTokenValid()) {
$util = new SDK($this->Config->findOneById(1));
$subscription = $util->getSubscriptionByChargeId($Order->getUnivapayChargeId());
$subscription = $subscription->cancel()->awaitResult();

return $this->json($subscription->status);
}

throw new BadRequestHttpException();
}

/**
* subscription get action
*
* @Method("GET")
* @Route("/univapay/subscription/get/{id}", requirements={"id" = "\d+"}, name="univa_pay_get_subscription")
*/
public function getSubscription(Request $request, Order $Order)
{
if ($request->isXmlHttpRequest() && $this->isTokenValid()) {
$util = new SDK($this->Config->findOneById(1));
$subscription = $util->getSubscriptionByChargeId($Order->getUnivapayChargeId());

return $this->json(['status' => $subscription->status, 'id' => $subscription->id]);
}

throw new BadRequestHttpException();
}

/**
* subscription update action
*
* @Method("POST")
* @Route("/univapay/subscription/update/{id}", requirements={"id" = "\d+"}, name="univa_pay_update_subscription")
*/
public function updateSubscription(Request $request, Order $Order)
{
if ($request->isXmlHttpRequest() && $this->isTokenValid()) {
$util = new SDK($this->Config->findOneById(1));
$subscription = $util->getSubscriptionByChargeId($Order->getUnivapayChargeId());
$subscription->patch($request->getContent());

return $this->json($subscription->status);
}

throw new BadRequestHttpException();
}
}
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM ghcr.io/5ym/ec-cube:4.1
RUN apk add git openssh-client
COPY . /var/lib/nginx/html/app/Plugin/UnivaPay
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,28 @@ UnivaPayの申し込み方法

## 開発環境

### 一般向け

1. 下記を参照にEC-CUBEを構築してください。
<https://github.com/EC-CUBE/ec-cube>
2. EC-CUBE管理画面よりプラグインをインストール
3. プラグインの設定画面よりSDKをインストール

### 管理者向け
vscode devcontainerを利用しています。

```sh
git clone https://github.com/univapaycast/UnivaPay-for-EC-CUBE4.git
cd EC-UnivaPay-for-EC-CUBE4
git clone https://github.com/univapay/UnivaPay-for-EC-CUBE4.git
cd UnivaPay-for-EC-CUBE4
cp docker-compose.sample.yml docker-compose.yml
docker compose up -d
docker compose exec web sh -c "composer run-script compile && bin/console eccube:install -n"
docker compose exec web sh -c "bin/console eccube:composer:require univapay/php-sdk && bin/console eccube:plugin:install --code=UnivaPay && bin/console eccube:plugin:enable --code=UnivaPay"
code . # devcontainerで開かなかったらdevcontainerで開きなおしてください
bin/console eccube:install -n
bin/console eccube:composer:require univapay/php-sdk
bin/console eccube:plugin:install --code=UnivaPay && bin/console eccube:plugin:enable --code=UnivaPay && bin/console cache:clear
```

#### データベース更新したとき
<http://localhost:1080>

### データベース更新したとき

```sh
docker compose exec web sh -c "bin/console eccube:install -n && bin/console eccube:plugin:install --code=UnivaPay && bin/console eccube:plugin:enable --code=UnivaPay"
bin/console eccube:install -n && bin/console eccube:plugin:install --code=UnivaPay && bin/console eccube:plugin:enable --code=UnivaPay
```

#### アップデート手順
### 管理者向けアップデート手順

1. composer.json内のversionを上げる
2. masterにコミット後github内でバージョンタグの作成
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
if(error === '0') {
alert("インストールに成功しました。");
} else if(error === '1') {
alert("インストールができませんでした。サーバ内で下記コマンドを実行してください。\nbin/console eccube:composer:require univapay/php-sdk:6.2.1");
alert("インストールができませんでした。サーバ内で下記コマンドを実行してください。\nbin/console eccube:composer:require univapay/php-sdk:6.5.0");
}
</script>
<form role="form" method="post">
Expand Down
Loading