
Product
Introducing GitHub Actions Scanning Support
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socket’s new workflow scanning support.
[!CAUTION] This gem is under development at pre-release stage
CoreMerchant is a library for customer, product, and subscription management in Rails applications. It's meant to be a starting point for building e-commerce and SaaS applications. It provides essential functionality for handling customers, products, and subscriptions. Does not include payment integrations.
Add this line to your application's Gemfile:
gem 'core_merchant', '~> 0.10.0'
and run bundle install.
Alternatively, you can install the gem manually:
$ gem install core_merchant
The steps below will guide you through setting up CoreMerchant in your Rails application. After completing these steps, you will be able to create subscription plans, manage subscriptions, and handle subscription events.
# Create a subscription plan
plan = CoreMerchant::SubscriptionPlan.create(name_key: 'basic', price_cents: 9_99, duration: '1m')
# Subscribe a customer to the plan
customer = current_user
subscription = CoreMerchant::Subscription.create(customer: customer, plan: plan)
# Start the subscription
CoreMerchant.subscription_manager.start_subscription(subscription)
# Use a listener to handle subscription events
class MySubscriptionListener
include CoreMerchant::SubscriptionListener
def on_subscription_started(subscription)
puts "Subscription started for #{subscription.customer.email}, subscribed to #{subscription.plan.name}"
end
def on_subscription_due_for_renewal(subscription)
puts "Subscription due for renewal for #{subscription.customer.email}, renewing until #{subscription.current_period_end_date}"
# After payment is processed
CoreMerchant.subscription_manager.payment_successful_for_renewal(subscription)
end
end
Run the generator to create the initializer file and the migrations:
$ rails generate core_merchant:install
This will create the following files:
config/initializers/core_merchant.rb - Configuration fileconfig/locales/core_merchant.en.yml - English translations for core merchant modelsdb/migrate/xxxxxx_create_core_merchant_subscription_plans.rb - Migration for subscription plansdb/migrate/xxxxxx_create_core_merchant_subscriptions.rb - Migration for subscriptions
You can then run the migrations:$ rails db:migrate
The initializer file config/initializers/core_merchant.rb contains the following configuration options:
config.customer_class = 'User'
This is the class that includes the CoreMerchant::Customer module. It should be the model class that represents your customers. For example, if you have a User model that represents your customers, you can include the CoreMerchant::Customer module in the User class:
# app/models/user.rb
class User < ApplicationRecord
include CoreMerchant::Customer
# ... the rest of your model code
end
config.subscription_listener_class = 'MySubscriptionListener'
This is the class that will receive subscription events. It should include the CoreMerchant::SubscriptionListener module and implement event handlers for the subscription events. Some examples:
class MySubscriptionListener
include CoreMerchant::SubscriptionListener
def on_test_event_received
puts 'Test event received, hooray!'
end
end
More about subscription events in the Handling subscription events section.
You can create a subscription plan using the SubscriptionPlan model:
CoreMerchant::SubscriptionPlan.create(name_key: 'basic', price_cents: 10_00, duration: '1m')
You can create a subscription for a customer using the Subscription model:
customer = User.find(1)
plan = CoreMerchant::SubscriptionPlan.find_by(name_key: 'basic')
subscription = CoreMerchant::Subscription.create(customer: customer, plan: plan)
Note that the subscription will not be active until you start it:
subscription.start
You can cancel a subscription by calling the cancel method. You can also specify a reason for the cancellation and whether the cancellation should take effect immediately or at the end of the current billing period:
subscription.cancel(reason: 'Customer request', at_period_end: false)
You can handle subscription events by implementing event handlers in the subscription listener class. For example, you can send an email to the customer when a subscription is created:
class MySubscriptionListener
include CoreMerchant::SubscriptionListener
def on_subscription_created(subscription)
FakeEmailService.send_email(subscription.customer.email, "We're happy to have you on board!")
# You can also start the subscription automatically
subscription.start
end
def on_subscription_started(subscription)
FakeEmailService.send_email(subscription.customer.email, "Your subscription has started!")
end
def on_subscription_due_for_renewal(subscription)
success = FakePaymentService.charge(subscription.customer, subscription.plan.price_cents)
if success
CoreMerchant.subscription_manager.payment_successful_for_renewal(subscription)
else
FakeEmailService.send_email(subscription.customer.email, "Payment failed, please update your payment method.")
CoreMerchant.subscription_manager.payment_failed_for_renewal(subscription)
end
end
def on_subscription_renewed(subscription)
FakeEmailService.send_email(subscription.customer.email, "Your subscription has been renewed until #{subscription.current_period_end_date}")
end
end
Available subscription events:
on_subscription_created(subscription)on_subscription_destroyed(subscription)on_subscription_started(subscription)on_subscription_canceled(subscription, reason:, at_period_end:)on_subscription_due_for_renewal(subscription)on_subscription_renewed(subscription)on_subscription_renewal_payment_processing(subscription)on_subscription_grace_period_started(subscription, days_remaining:)CoreMerchant now keeps a detailed history of subscription events, including creations, renewals, cancellations, status changes, and plan changes. This provides an audit trail and can be useful for debugging, customer support, and analytics.
To access a subscription's history:
subscription = CoreMerchant::Subscription.find(42)
# Get all events
subscription.subscription_events
# Get specific event types
latest_renewal = subscription.renewal_events.last
puts "Last renewed at: #{latest_renewal.created_at}"
puts "Renewal price: #{latest_renewal.price_cents} cents, renewed until: #{latest_renewal.renewed_until}"
latest_status_change = subscription.status_change_events.last
puts "Status changed from #{latest_status_change.from} to #{latest_status_change.to}"
latest_plan_change = subscription.plan_change_events.last
puts "Plan changed from #{latest_plan_change.from_plan.name} to #{latest_plan_change.to_plan.name}"
Access from CoreMerchant.subscription_manager. The SubscriptionManager class is responsible for managing subscriptions. It is responsible for notifying listeners when subscription events occur and checking for and handling renewals.
Attributes:
listeners - An array of listeners that will be notified when subscription events occur.Methods:
check_subscriptions - Checks all subscriptions for renewalsadd_listener(listener) - Adds a listener to the list of listenersno_payment_needed_for_renewal(subscription) - Handles the case where no payment is needed for a renewal.
Call when a subscription is renewed without payment.processing_payment_for_renewal(subscription) - Handles the case where payment is being processed for a renewal.
Call when payment is being processed for a renewal.payment_successful_for_renewal(subscription) - Handles the case where payment was successful for a renewal.
Call when payment was successful for a renewal.payment_failed_for_renewal(subscription) - Handles the case where payment failed for a renewal.
Call when payment failed for a renewal.Usage:
manager = CoreMerchant.subscription_manager
manager.check_subscriptions
# ... somewhere else in the code ...
manager.payment_successful_for_renewal(subscription1)
manager.payment_failed_for_renewal(subscription2)
The SubscriptionPlan model represents a subscription plan in your application. Subscription plans are used to define the pricing and features of a subscription. All prices are in cents.
Attributes:
name_key: A unique key for the subscription plan.
This key is used to identify the plan in the application,
as well as the translation key for the plan name through core_merchant.subscription_plans.price_cents: The price of the subscription plan in cents.duration: The duration of the subscription plan.
Consists of a number and a letter representing the time unit as day, week, month, or year.
For example, 1w for 1 week, 3m for 3 months, 1y for 1 year.introductory_price_cents: The introductory price of the subscription plan in cents.introductory_duration: The duration of the introductory price of the subscription plan.Usage:
plan = CoreMerchant::SubscriptionPlan.new(name_key: "basic_monthly", price_cents: 7_99)
plan.save
Represents a subscription in CoreMerchant. This class manages the lifecycle of a customer's subscription to a specific plan.
Subscriptions can transition through various statuses:
pending: Subscription created but not yet startedtrial: In a trial periodactive: Currently active and paidpast_due: Payment failed but in grace periodpending_cancellation: Will be canceled at period endprocessing_renewal: Renewal in progressprocessing_payment: Payment processingcanceled: Canceled by user or due to payment failureexpired: Subscription period endedpaused: Temporarily halted, not yet implementedpending_change: Plan change scheduled for next renewal, not yet implementedKey features:
Attributes:
customer: Polymorphic association to the customersubscription_plan: The current plan for this subscriptionstatus: Current status of the subscription (see enum definition)start_date: When the subscription startedend_date: When the subscription ended (or will end)trial_end_date: End date of the trial period (if applicable)canceled_at: When the subscription was canceledcurrent_period_start: Start of the current billing periodcurrent_period_end: End of the current billing periodpause_start_date: When the subscription was pausedpause_end_date: When the paused subscription will resumecurrent_period_price_cents: Price for the current periodnext_renewal_price_cents: Price for the next renewal (if different from plan)cancellation_reason: Reason for cancellation (if applicable)Methods:
start - Starts the subscriptioncancel(reason:, at_period_end:) - Cancels the subscription, optionally at the end of the current periodUsage:
subscription = CoreMerchant::Subscription.create(customer: user, subscription_plan: plan, status: :active)
subscription.start
subscription.cancel(reason: "Too expensive", at_period_end: true)
The SubscriptionEvent model represents a historical log of events related to a subscription. It provides an audit trail of all significant actions and state changes for a subscription.
This class has subclasses for specific event types, such as SubscriptionRenewalEvent, SubscriptionStatusChangeEvent, and SubscriptionPlanChangeEvent. Each subclass has additional fields specific to the event type.
Attributes:
subscription: Association to the related Subscriptionevent_type: Type of the event (e.g., 'created', 'renewed', 'canceled', 'status_changed', 'plan_changed')metadata: JSON field for storing additional event-specific dataUsage:
# Automatically logged when a subscription is created
subscription = CoreMerchant::Subscription.create(customer: user, subscription_plan: plan)
# Logging a custom event
subscription.log_event('custom_event', key: 'value')
# Retrieve the last renewal event
latest_renewal = subscription.renewal_events.last
puts "Last renewed at: #{latest_renewal.created_at}"
puts "Renewal price: #{latest_renewal.price_cents} cents, renewed until: #{latest_renewal.renewed_until}"
# Retrieve the last event of any type
latest_event = subscription.subscription_events.last
puts "Last event type: #{latest_event.event_type}, metadata: #{latest_event.metadata}"
price_cents: The price of the renewal in centsrenewed_until: The end date of the renewalrenewed_at: The date and time of the renewalfrom: The previous status of the subscriptionto: The new status of the subscriptionfrom_plan: The previous plan of the subscriptionto_plan: The new plan of the subscriptionreason: The reason for the cancellationat_period_end: Whether the cancellation is scheduled for the end of the current periodcanceled_at: The date and time of the cancellation[!NOTE] Other models and features are being developed and will be added in future releases.
Bug reports and pull requests are welcome on GitHub at https://github.com/theseyithan/core_merchant
FAQs
Unknown package
We found that core_merchant demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socket’s new workflow scanning support.

Product
Add real-time Socket webhook events to your workflows to automatically receive pull request scan results and security alerts in real time.

Research
The Socket Threat Research Team uncovered malicious NuGet packages typosquatting the popular Nethereum project to steal wallet keys.