diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d87b5b1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,112 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a Ruby gem that provides a client library for the Midtrans Payment Gateway API. The gem wraps various Midtrans API endpoints (payment transactions, virtual accounts, disbursements, merchant management, etc.) with a clean Ruby interface. + +## Development Commands + +### Running Tests +```bash +rake spec # Run all tests +bundle exec rspec spec/path/to/file_spec.rb # Run specific test file +bundle exec rspec spec/path/to/file_spec.rb:LINE # Run specific test at line +``` + +### Interactive Console +```bash +bin/console # IRB console with the gem loaded +``` + +### Build and Install +```bash +bundle exec rake install # Install gem locally +bundle exec rake release # Release new version (tags, pushes to rubygems) +``` + +## Architecture + +### Client Architecture +The gem follows a layered architecture pattern: + +1. **Client Layer** (`lib/midtrans_api/client.rb`) + - Main entry point that users interact with + - Manages Faraday HTTP connection with Basic Auth + - Provides convenience methods that return API instances (e.g., `client.gopay_charge`, `client.merchant`) + - Supports three API environments via configuration: production, sandbox, and partner API + - HTTP methods: `get()`, `post()`, `patch()` + +2. **API Layer** (`lib/midtrans_api/api/*`) + - Each API endpoint has its own class that inherits from `MidtransApi::Api::Base` + - Organized by feature domain (e.g., `Merchant::Create`, `Gopay::Charge`, `Transaction::Expire`) + - API classes define the endpoint `PATH` constant and HTTP method (e.g., `post()`, `patch()`) + - Responsible for making HTTP requests via the client and returning Model instances + +3. **Model Layer** (`lib/midtrans_api/model/*`) + - Each API response is mapped to a Model class that inherits from `MidtransApi::Model::Base` + - Models use `resource_attributes` macro to define accessible response fields + - Base class handles initialization from API response hash via `assign_attributes` + - Models implement `resolve_params_attr()` for key transformation (typically identity transform) + +4. **Configuration** (`lib/midtrans_api/configure.rb`) + - Manages API credentials (client_key, server_key) + - Environment selection (sandbox vs production vs partner API) + - Optional features: notification URL override, logging, timeout settings + +### Adding New API Endpoints + +To add a new Midtrans API endpoint: + +1. **Create API class** at `lib/midtrans_api/api/{domain}/{action}.rb`: + ```ruby + class MyApi < MidtransApi::Api::Base + PATH = 'endpoint/path' + + def post(params, additional_headers_params) + response = client.post(PATH, params, { + 'X-CUSTOM-HEADER': additional_headers_params + }) + MidtransApi::Model::Domain::MyApi.new(response) + end + end + ``` + +2. **Create Model class** at `lib/midtrans_api/model/{domain}/{action}.rb`: + ```ruby + class MyApi < MidtransApi::Model::Base + resource_attributes :field1, :field2, :field3 + + def resolve_params_attr(attr) + attr.to_s # or custom transformation + end + end + ``` + +3. **Register in Client** (`lib/midtrans_api/client.rb`): + - Add `require` statements at the top for both API and Model files + - Add convenience method to instantiate the API class: + ```ruby + def my_api + @my_api ||= MidtransApi::Api::Domain::MyApi.new(self) + end + ``` + - If using new HTTP verb, add method (e.g., `put()`, `delete()`) + +4. **Create test file** at `spec/lib/midtrans_api/api/{domain}/{action}_spec.rb`: + - Use WebMock to stub HTTP requests + - Test that correct model instance is returned + - Test that proper headers are sent + - Follow pattern from existing specs (e.g., `merchant/create_spec.rb`) + +### Error Handling +- Custom errors defined in `lib/midtrans_api/errors.rb` +- Middleware `HandleResponseException` intercepts HTTP errors and raises appropriate exceptions +- See Midtrans API documentation for status codes + +### Logging and Security +- Uses Faraday middleware for logging +- `FaradayLogFormatter` provides custom log formatting +- `JsonMasker` and `UrlMasker` utilities mask sensitive data in logs +- Configure via `filtered_logs` and `mask_params` client options diff --git a/README.md b/README.md index 9e42960..6650be2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,25 @@ -# midtrans_api_ruby +# Midtrans API Ruby Client -Midtrans API client library for Ruby +A Ruby client library for the [Midtrans Payment Gateway API](https://api-docs.midtrans.com/). This gem provides a clean and intuitive interface to interact with Midtrans services including payment transactions, virtual accounts, disbursements, and merchant management. + +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT) + +## Table of Contents + +- [Installation](#installation) +- [Configuration](#configuration) +- [Usage](#usage) + - [Credit Card Payments](#credit-card-payments) + - [GoPay Payments](#gopay-payments) + - [Bank Transfer / Virtual Account](#bank-transfer--virtual-account) + - [Transaction Management](#transaction-management) + - [Merchant Management](#merchant-management) + - [Disbursements](#disbursements) + - [Utilities](#utilities) +- [Error Handling](#error-handling) +- [Development](#development) +- [Contributing](#contributing) +- [License](#license) ## Installation @@ -12,306 +31,440 @@ gem 'mekari-midtrans-api' And then execute: - $ bundle +```bash +$ bundle install +``` Or install it yourself as: - $ gem install mekari-midtrans-api +```bash +$ gem install mekari-midtrans-api +``` -## Usage +## Configuration -### Build client +### Basic Configuration ```ruby require 'midtrans_api' midtrans = MidtransApi::Client.new( client_key: 'YOUR-CLIENT-KEY', server_key: 'YOUR-SERVER-KEY', - sandbox: true|false, - notification_url: 'https://example.com/callback', - filtered_logs: %[word1 word2], - logger: Logger.new(STDOUT), - timeout: 30 # by default will be 60 (seconds) + sandbox: true, # Set to false for production + timeout: 30 # Optional, default is 60 seconds ) -# or - -midtrans = MidtransApi::Client.new do |client| - client.client_key = 'YOUR-CLIENT-KEY' - client.server_key = 'YOUR-SERVER-KEY' - client.sandbox_mode = true|false - client.notification_url = 'https://example.com/callback' +# Using block initialization +midtrans = MidtransApi::Client.new do |config| + config.client_key = 'YOUR-CLIENT-KEY' + config.server_key = 'YOUR-SERVER-KEY' + config.sandbox_mode = true end ``` -### Basic usage +### Advanced Configuration -#### Credit Card Online Installment Charge ```ruby -# get credit card token +midtrans = MidtransApi::Client.new( + client_key: 'YOUR-CLIENT-KEY', + server_key: 'YOUR-SERVER-KEY', + sandbox: false, + notification_url: 'https://example.com/callback', # Override notification URL + logger: Logger.new(STDOUT), # Enable logging + filtered_logs: %w[card_number card_cvv], # Filter sensitive data from logs + mask_params: %w[token_id], # Mask specific parameters + timeout: 30 # Request timeout in seconds +) +``` + +## Usage + +### Credit Card Payments + +#### Get Credit Card Token +```ruby credit_card_params = { currency: 'IDR', gross_amount: 12500, card_number: 5573381072196900, - card_exp_month: 02, + card_exp_month: 2, card_exp_year: 2025, card_cvv: 123 } -credit_card_token = midtrans.credit_card_token.get(credit_card_params) -#=> credit_card_token returns MidtransApi::Model::CreditCard::Token instance +token = midtrans.credit_card_token.get(credit_card_params) +# Returns: MidtransApi::Model::CreditCard::Token +``` +#### Charge with Installment + +```ruby charge_params = { - "payment_type": 'credit_card', - "transaction_details": { - "order_id": 'order-with-credit_card_installment', - "gross_amount": 12500 + payment_type: 'credit_card', + transaction_details: { + order_id: 'order-101', + gross_amount: 12500 }, - "credit_card": { - "token_id": credit_card_token.token_id, - "authentication": true, - "installment_term": 3, - "bank": 'mandiri', - "bins": [ - 'mandiri' - ] + credit_card: { + token_id: token.token_id, + authentication: true, + installment_term: 3, + bank: 'mandiri' }, - "customer_details": { - "first_name": 'Budi', - "last_name": 'Utomo', - "email": 'test@midtrans.com', - "phone": '081111333344' + customer_details: { + first_name: 'Budi', + last_name: 'Utomo', + email: 'test@midtrans.com', + phone: '081111333344' }, - "item_details": [ + item_details: [ { - "id": 'invoice-1', - "price": 12500, - "quantity": 1, - "name": 'Invoice #1' + id: 'invoice-1', + price: 12500, + quantity: 1, + name: 'Invoice #1' } ] } -credit_card_charge = midtrans.credit_card_charge.post(charge_params) -#=> credit_card_charge returns MidtransApiMidtransApi::Model::CreditCard::Charge instance +charge = midtrans.credit_card_charge.post(charge_params) +# Returns: MidtransApi::Model::CreditCard::Charge ``` -#### Gopay Charge +### GoPay Payments + ```ruby charge_params = { - "payment_type": "gopay", - "transaction_details": { - "order_id": "order-with-gopay", - "gross_amount": 12500 + payment_type: 'gopay', + transaction_details: { + order_id: 'order-102', + gross_amount: 12500 }, - "item_details": [ - { - "id": "bluedio-turbine", - "price": 12500, - "quantity": 1, - "name": "Bluedio H+ Turbine Headphone with Bluetooth 4.1 -" - } + item_details: [ + { + id: 'item-1', + price: 12500, + quantity: 1, + name: 'Product Name' + } ], - "customer_details": { - "first_name": "Budi", - "last_name": "Utomo", - "email": "budi.utomo@midtrans.com", - "phone": "081223323423" + customer_details: { + first_name: 'Budi', + last_name: 'Utomo', + email: 'budi.utomo@midtrans.com', + phone: '081223323423' }, - "gopay": { - "enable_callback": true, - "callback_url": "someapps://callback" + gopay: { + enable_callback: true, + callback_url: 'someapps://callback' } } -gopay_charge = midtrans.gopay_charge.post(charge_params) -#=> gopay_charge returns MidtransApiMidtransApi::Model::Gopay::Charge instance +charge = midtrans.gopay_charge.post(charge_params) +# Returns: MidtransApi::Model::Gopay::Charge ``` -#### BCA Virtual Account Charge +### Bank Transfer / Virtual Account + +#### BCA Virtual Account + ```ruby charge_params = { - "payment_type": "bank_transfer", - "transaction_details": { - "order_id": "order-with-bca-virtua-account", - "gross_amount": 12500 + payment_type: 'bank_transfer', + transaction_details: { + order_id: 'order-103', + gross_amount: 12500 }, - "item_details": [ - { - "id": "bluedio-turbine", - "price": 12500, - "quantity": 1, - "name": "Bluedio H+ Turbine Headphone with Bluetooth 4.1 -" - } + item_details: [ + { + id: 'item-1', + price: 12500, + quantity: 1, + name: 'Product Name' + } ], - "customer_details": { - "first_name": "Budi", - "last_name": "Utomo", - "email": "budi.utomo@midtrans.com", - "phone": "081223323423" + customer_details: { + first_name: 'Budi', + last_name: 'Utomo', + email: 'budi.utomo@midtrans.com', + phone: '081223323423' }, - "bank_transfer": { - "bank": "bca", - "va_number": "11111111", - "free_text": { - "inquiry": [ - { - "id": "Free Text Inquiry ID", - "en": "Free Text Inquiry EN" - } - ], - "payment": [ - { - "id": "Free Text Payment ID", - "en": "Free Text Payment EN" - } - ] + bank_transfer: { + bank: 'bca', + va_number: '11111111', + free_text: { + inquiry: [{ id: 'Free Text Inquiry ID', en: 'Free Text Inquiry EN' }], + payment: [{ id: 'Free Text Payment ID', en: 'Free Text Payment EN' }] } }, - "bca": { - "sub_company_code": "000" - } + bca: { + sub_company_code: '000' + } } -bca_virtual_account_charge = midtrans.bca_virtual_account_charge.post(charge_params) -#=> bca_virtual_account_charge returns MidtransApiMidtransApi::Model::BcaVirtualAccount::Charge instance +charge = midtrans.bca_virtual_account_charge.post(charge_params) +# Returns: MidtransApi::Model::BcaVirtualAccount::Charge ``` -#### Expire Transaction -```ruby -expire_response = midtrans.expire_transaction.post(order_id: "eb046679-285a-4136-8977-e4c429cc3254") -#=> expire_response returns MidtransApiMidtransApi::Model::Transaction::Expire instance -``` - -#### Charge Transaction -Charge Transaction Payment Method: **Bank Transfer** -_Bank Transfer_ is one of the payment methods offered by Midtrans. By using this method, your customers can make a payment via bank transfer and Midtrans will send real time notification when the payment is completed. - -A list of bank transfer payment methods supported by Midtrans is given below. +#### Other Bank Virtual Accounts -- Permata Virtual Account -- BCA Virtual Account (Please refer to BCA Virtual Account Charge section) -- Mandiri Bill Payment -- BNI Virtual Account -- BRI Virtual Account -- CIMB Virtual Account +Supported banks: Permata, BNI, BRI, CIMB -##### Charge transaction ```ruby -# "payment_type" => required <"bank_transfer"|"echannel"> -# "transaction_details" => required -# "customer_details" => optional -# "item_details" => optional -# "bank_transfer"|"echannel" => required -charge_params_bank_transfer = { - "payment_type": "bank_transfer", - "transaction_details": { - "gross_amount": 10000, - "order_id": "{{$timestamp}}" # specified by you - }, - "customer_details": { - "email": "budi.utomo@Midtrans.com", - "first_name": "budi", - "last_name": "utomo", - "phone": "+6281 1234 1234" - }, - "item_details": [ +charge_params = { + payment_type: 'bank_transfer', + transaction_details: { + gross_amount: 10000, + order_id: 'order-104' + }, + customer_details: { + email: 'budi.utomo@midtrans.com', + first_name: 'Budi', + last_name: 'Utomo', + phone: '+6281 1234 1234' + }, + item_details: [ { - "id": "1388998298204", - "price": 5000, - "quantity": 1, - "name": "Ayam Zozozo" + id: '1388998298204', + price: 5000, + quantity: 1, + name: 'Item A' }, { - "id": "1388998298205", - "price": 5000, - "quantity": 1, - "name": "Ayam Xoxoxo" + id: '1388998298205', + price: 5000, + quantity: 1, + name: 'Item B' } - ], - "bank_transfer":{ - "bank": "bni|bri|permata|cimb", - "va_number": "111111" + ], + bank_transfer: { + bank: 'bni', # Options: bni, bri, permata, cimb + va_number: '111111' } } -charge_params_echannel = { - "payment_type": "echannel", - "transaction_details": { - "order_id": "1388", # specified by you - "gross_amount": 95000 - }, - "item_details": [ - { - "id": "a1", - "price": 50000, - "quantity": 2, - "name": "Apel" - }, - { - "id": "a2", - "price": 45000, - "quantity": 1, - "name": "Jeruk" - } - ], - "echannel": { - "bill_info1": "Payment For:", - "bill_info2": "debt", - "bill_key": "081211111111" +charge = midtrans.charge_transaction.post(charge_params, 'bank_transfer') +# Returns: MidtransApi::Model::Transaction::Charge +``` + +#### Mandiri Bill Payment (E-Channel) + +```ruby +charge_params = { + payment_type: 'echannel', + transaction_details: { + order_id: 'order-105', + gross_amount: 95000 + }, + item_details: [ + { + id: 'a1', + price: 50000, + quantity: 2, + name: 'Apel' + }, + { + id: 'a2', + price: 45000, + quantity: 1, + name: 'Jeruk' } + ], + echannel: { + bill_info1: 'Payment For:', + bill_info2: 'Debt', + bill_key: '081211111111' + } } -charge_response = midtrans.charge_transaction.post(charge_params_bank_transfer, "bank_transfer") # => payment type bank_transfer -charge_response = midtrans.charge_transaction.post(charge_params_echannel, "echannel") # => payment type echannel -#=> charge_response returns MidtransApiMidtransApi::Model::Transaction::Charge instance +charge = midtrans.charge_transaction.post(charge_params, 'echannel') +# Returns: MidtransApi::Model::Transaction::Charge +``` + +### Transaction Management + +#### Check Transaction Status + +```ruby +status = midtrans.status.get(order_id: 'order-101') +# Returns: MidtransApi::Model::Check::Status + +# Access response attributes +puts status.transaction_status # e.g., 'settlement', 'pending', 'cancel' +puts status.order_id +puts status.gross_amount +``` + +#### Expire Transaction + +```ruby +expire_response = midtrans.expire_transaction.post(order_id: 'order-101') +# Returns: MidtransApi::Model::Transaction::Expire ``` -#### Charge Transaction with Custom Expiry +#### Custom Expiry + ```ruby -charge_params_with_custom_expiry = { - "payment_type": "bank_transfer", - "bank_transfer": { - "bank": "permata" +charge_params = { + payment_type: 'bank_transfer', + bank_transfer: { + bank: 'permata' }, - "transaction_details": { - "order_id": "C17550", - "gross_amount": 145000 + transaction_details: { + order_id: 'order-106', + gross_amount: 145000 }, - "custom_expiry": { - "order_time": "2016-12-07 11:54:12 +0700", # If not defined, expiry time starts from transaction time. - "expiry_duration": 60, - "unit": "second|minute|hour|day" # default is minute + custom_expiry: { + order_time: '2024-12-07 11:54:12 +0700', # Optional: defaults to current time + expiry_duration: 60, + unit: 'minute' # Options: second, minute, hour, day } } -charge_response = midtrans.charge_transaction.post(charge_params_with_custom_expiry, "bank_transfer|echannel") -#=> charge_response returns MidtransApiMidtransApi::Model::Transaction::Charge instance +charge = midtrans.charge_transaction.post(charge_params, 'bank_transfer') +# Returns: MidtransApi::Model::Transaction::Charge +``` + +### Merchant Management + +#### Create Merchant + +```ruby +merchant_params = { + email: 'merchant@midtrans.com', + merchant_name: 'My Merchant', + callback_url: 'https://merchant.com/midtrans-callback', + notification_url: 'https://merchant.com/midtrans-notification', + pay_account_url: 'https://merchant.com/pay-account-notification', + owner_name: 'Owner Name', + merchant_phone_number: '81211111111', + mcc: 'Event', + entity_type: 'corporate', + business_name: 'PT Business Name' +} + +merchant = midtrans.merchant.post(merchant_params, 'partner_id') +# Returns: MidtransApi::Model::Merchant::Create +``` + +#### Update Merchant Notification URLs + +```ruby +notification_params = { + payment_notification_url: 'https://merchant.com/payment-notification', + iris_notification_url: 'https://merchant.com/payout-notification', + recurring_notification_url: 'https://merchant.com/recurring-notification', + pay_account_notification_url: 'https://merchant.com/pay-account-notification', + finish_payment_redirect_url: 'https://merchant.com/payment-finish' +} + +response = midtrans.merchant_update_notification.patch( + notification_params, + 'partner_id', + 'merchant_id' +) +# Returns: MidtransApi::Model::Merchant::UpdateNotification +``` + +### Disbursements + +#### Create Payout + +```ruby +payout_params = { + payouts: [ + { + beneficiary_name: 'John Doe', + beneficiary_account: '1234567890', + beneficiary_bank: 'bca', + beneficiary_email: 'john@example.com', + amount: 100000, + notes: 'Payout for invoice #123' + } + ] +} + +payout = midtrans.payout.post(payout_params) +# Returns: MidtransApi::Model::Disbursement::Payout ``` -#### Check Status Payment +### Utilities + +#### Check Balance + ```ruby -dummy_order_id = "order-with-gopay" -check_status = midtrans.status.get(order_id: dummy_order_id) -#=> check_status returns MidtransApi::Model::Check::Status +balance = midtrans.balance.get +# Returns: MidtransApi::Model::Check::Balance ``` -About official documentation api of Midtrans API, see [API doc](https://api-docs.midtrans.com/) +#### List Channels -### Errors (Sample) -MidtransApi can raise conditional Errors explained from Midtrans Documentation. -About available Status Code, see [Midtrans API doc](https://api-docs.midtrans.com/#status-code) +```ruby +channels = midtrans.channel.get('partner_id', 'merchant_id') +# Returns: Array of channels with virtual account information +``` + +## Error Handling + +The gem raises custom exceptions for various error scenarios: + +```ruby +begin + charge = midtrans.gopay_charge.post(charge_params) +rescue MidtransApi::Errors::ApiError => e + puts "API Error: #{e.message}" + puts "Status Code: #{e.status_code}" +rescue MidtransApi::Errors::AuthenticationError => e + puts "Authentication failed: #{e.message}" +rescue MidtransApi::Errors::ValidationError => e + puts "Validation failed: #{e.message}" +end +``` + +For more information about status codes and error handling, see the [Midtrans API documentation](https://api-docs.midtrans.com/#status-code). ## Development -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +After checking out the repo, run the following to set up your development environment: + +```bash +$ bin/setup # Install dependencies +$ rake spec # Run all tests +$ bin/console # Interactive console for experimentation +``` + +### Running Specific Tests + +```bash +$ bundle exec rspec spec/path/to/file_spec.rb # Run specific test file +$ bundle exec rspec spec/path/to/file_spec.rb:42 # Run test at specific line +``` + +### Building and Installing Locally + +```bash +$ bundle exec rake install # Install gem locally +$ bundle exec rake release # Release new version (creates git tag, pushes to rubygems) +``` + +## API Documentation -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). +For complete API documentation and reference, visit: +- [Midtrans API Documentation](https://api-docs.midtrans.com/) +- [Midtrans Dashboard](https://dashboard.midtrans.com/) ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/mekari-engineering/midtrans_api_ruby. +To contribute: +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/my-new-feature`) +3. Write tests for your changes +4. Ensure all tests pass (`rake spec`) +5. Commit your changes (`git commit -am 'Add some feature'`) +6. Push to the branch (`git push origin feature/my-new-feature`) +7. Create a Pull Request ## License diff --git a/lib/midtrans_api/api/merchant/update_notification.rb b/lib/midtrans_api/api/merchant/update_notification.rb new file mode 100644 index 0000000..b55502f --- /dev/null +++ b/lib/midtrans_api/api/merchant/update_notification.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module MidtransApi + module Api + module Merchant + class UpdateNotification < MidtransApi::Api::Base + PATH = 'merchants/notifications' + + def patch(params, partner_id, merchant_id) + response = client.patch(PATH, params, { + 'X-PARTNER-ID': partner_id, + 'X-MERCHANT-ID': merchant_id + }) + + MidtransApi::Model::Merchant::UpdateNotification.new(response) + end + end + end + end +end diff --git a/lib/midtrans_api/client.rb b/lib/midtrans_api/client.rb index 2e28944..9deaf40 100644 --- a/lib/midtrans_api/client.rb +++ b/lib/midtrans_api/client.rb @@ -14,6 +14,7 @@ require 'midtrans_api/api/check/balance' require 'midtrans_api/api/disbursement/payout' require 'midtrans_api/api/merchant/create' +require 'midtrans_api/api/merchant/update_notification' require 'midtrans_api/api/merchant/get' require 'midtrans_api/api/channel/list' @@ -31,6 +32,7 @@ require 'midtrans_api/model/check/balance' require 'midtrans_api/model/disbursement/payout' require 'midtrans_api/model/merchant/create' +require 'midtrans_api/model/merchant/update_notification' require 'midtrans_api/model/merchant/get' module MidtransApi @@ -106,6 +108,10 @@ def merchant @merchant ||= MidtransApi::Api::Merchant::Create.new(self) end + def merchant_update_notification + @merchant_update_notification ||= MidtransApi::Api::Merchant::UpdateNotification.new(self) + end + def get_merchant @merchant_get ||= MidtransApi::Api::Merchant::Get.new(self) end @@ -124,6 +130,11 @@ def post(url, params, headers = {}) response.body end + def patch(url, params, headers = {}) + response = @connection.patch(url, params, headers) + response.body + end + private def find_logger(logger_options) diff --git a/lib/midtrans_api/model/merchant/update_notification.rb b/lib/midtrans_api/model/merchant/update_notification.rb new file mode 100644 index 0000000..92855da --- /dev/null +++ b/lib/midtrans_api/model/merchant/update_notification.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module MidtransApi + module Model + module Merchant + class UpdateNotification < MidtransApi::Model::Base + resource_attributes :status_code, + :status_message, + :payment_notification_url, + :iris_notification_url, + :recurring_notification_url, + :pay_account_notification_url, + :finish_payment_redirect_url + + def resolve_params_attr(attr) + attr.to_s + end + end + end + end +end diff --git a/spec/lib/midtrans_api/api/merchant/update_notification_spec.rb b/spec/lib/midtrans_api/api/merchant/update_notification_spec.rb new file mode 100644 index 0000000..dd7c498 --- /dev/null +++ b/spec/lib/midtrans_api/api/merchant/update_notification_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MidtransApi::Api::Merchant::UpdateNotification do + let(:client) do + MidtransApi::Client.new( + client_key: 'secret_key', + server_key: 'secret_key', + sandbox: true, + api_version: :v1 + ) + end + + let(:params) do + { + "payment_notification_url": "https://merchant.com/midtrans-payment-notification", + "iris_notification_url": "https://merchant.com/midtrans-payout-notification", + "recurring_notification_url": "https://merchant.com/midtrans-recurring-notification", + "pay_account_notification_url": "https://merchant.com/midtrans-pay-account-notification", + "finish_payment_redirect_url": "https://merchant.com/payment-finish" + } + end + + let(:success_response) do + { + "status_code": "200", + "status_message": "Notification URLs updated successfully", + "payment_notification_url": "https://merchant.com/midtrans-payment-notification", + "iris_notification_url": "https://merchant.com/midtrans-payout-notification", + "recurring_notification_url": "https://merchant.com/midtrans-recurring-notification", + "pay_account_notification_url": "https://merchant.com/midtrans-pay-account-notification", + "finish_payment_redirect_url": "https://merchant.com/payment-finish" + } + end + + describe '#patch' do + it 'returns expected response' do + stub_request(:patch, "#{client.config.api_url}/#{client.config.api_version}/merchants/notifications").to_return( + status: 200, body: success_response.to_json + ) + + update_notification_api = described_class.new(client) + response = update_notification_api.patch(params, 'partner_id', 'merchant_id') + expect(response).to be_instance_of MidtransApi::Model::Merchant::UpdateNotification + expect(response.status_code).to eq(success_response[:status_code]) + expect(response.payment_notification_url).to eq(success_response[:payment_notification_url]) + expect(response.iris_notification_url).to eq(success_response[:iris_notification_url]) + end + + it 'sends required headers' do + request = stub_request(:patch, "#{client.config.api_url}/#{client.config.api_version}/merchants/notifications") + .with( + headers: { + 'X-PARTNER-ID': 'test_partner_id', + 'X-MERCHANT-ID': 'test_merchant_id' + } + ) + .to_return(status: 200, body: success_response.to_json) + + update_notification_api = described_class.new(client) + update_notification_api.patch(params, 'test_partner_id', 'test_merchant_id') + + expect(request).to have_been_requested + end + end +end