====== LRS PRICING MODEL====== ===== Requirement ======= Implement pricing model for LRS based on the statements per billing period. ===== Difference from Learnexa ======= - Learnexa - All the sites will have the same subscription period (which is configured at super site.) - LRS - As expertus one customers each of them may have different billing periods (some may have annual, some may have quarterly), each site's billing period is configured differently per site. - Super admin can set offline payment to any subsite under site subscription page(This will be like flag super site admin can set it, if it set's true to any subsite that site should not have the "subscribe now" notification bar) ===== Design and Implementation ======= LRS pricing model implementation is similar to learnexa pricing model, Subsite can be billable based on the statements per period. So the plan is similar to learnexa where admin can set the subscription setting, subscription plan and that can be used for subsite subscription. If the price of the subscription changes then the user shall be notified, A User will have an option to Un-subscribe at any time. User can change the pricing plan either by the end of the period or middle of the period. **Trail period** There will be a trail period for few days that can be configured by super site admin in the subscription settings under the site subscription tab. **Subscription** There will be a various subscription plan which can be created and maintained by the super site admin. Super site admin can assign the default/custom subscription to the subsite. Subsite admin has to subscribe in order to use the site and the statements,Which is similar to learnexa. **eg:** a) FREE - 500 Statements - $0.00 b) PlanA - 2000 Statements - $20.00 c) PlanB - 5000 Statements - $40.00 d) PlanC - 10000 Statements - $70.00 ** Subscription Type** a) Day b) Week c) 2Week d) Monthly e) Quarterly f) Yearly **Overage Statements** Statements count will be tracked, if the statement count exceeds the subscribed plan count, overage statements will be notified to the user and that will be billable, The overage statement and the pricing information will be shown under the Billing tab, Subsite admin has to pay it from billing page. ===== Models ====== The following Models will be used for Implementation class Company < ActiveRecord::Base #This model already exists just add below association belongs_to :site_subscription has_one :merchant_account, :as => :owner has_many :statements, :through => :client_applications has_many :site_orders, :through => :site_subscription end class SubscriptionSetting < ActiveRecord::Base end class SubscriptionPlan < ActiveRecord::Base has_many :site_subscriptions has_many :site_orders has_many :site_custom_plans , :dependent => :destroy end class SiteCustomPlan < ActiveRecord::Base belongs_to :subscription_plan belongs_to :site_subscription end class SiteSubscription < ActiveRecord::Base belongs_to :subscription_plan has_one :company, :dependent => :destroy has_many :site_orders has_many :site_order_items, :through => :site_orders, :dependent => :destroy has_many :payments_made, :class_name => "SitePayment", :foreign_key => "payer_id" has_many :site_usages has_one :site_custom_plan, :dependent => :destroy has_one :custom_plan, :through => :site_custom_plan, :source => :subscription_plan end class SiteOrder < ActiveRecord::Base belongs_to :site_subscription belongs_to :subscription_plan has_one :site_payment, :dependent => :destroy has_many :site_order_items, :dependent => :destroy end class SiteOrderItem < ActiveRecord::Base belongs_to :site_order belongs_to :item, :polymorphic => true end class SitePayment < ActiveRecord::Base belongs_to :site_order belongs_to :payer, :class_name => "SiteSubscription" belongs_to :user_paid, :class_name => "User", :foreign_key => "payer_user_id" end ===== DataBase Table Schema ===== Table Name: **companies**(This table already exists. Just add following columns) ^ Column_name ^type ^ Description ^ |site_subscription_id | integer | ID of the subscription ID corresponding to the company | Table Name: **subscription_settings** ^ Column_name ^type ^ Description ^ | id | integer | primary key | | trial_period | string | day/week/2 week/month/quarter/year | | delete_lag | integer | Time left to delete the site after expiry | | expiry_reminder_lag | string | Time before expiry date to send trial expiry reminder | | expired_notification_lag | string | Time after expiry to send trial expired notification | | site_lock_lag | integer | Time left to lock the site after the auto renewal of subscription failed | |create_at| date_time |created date | |updated_at| date_time|updated date | Table Name: **subscription_plans** ^ Column_name ^type ^ Description ^ | id | integer | primary key | | name | string | subscription name | | code | string | subscription unique code | | subscription_period | string | day/week/2 week/month/quarter/year | | price | Float | Subscription Price | | statement_pack_size(Learnexa: max_active_user_count) | integer | Maximum Statement for the price | | additional_per_statement_cost(Learnexa: per_user_cost ) | float | Additional statement fees | | additional_statement_pack_size(Learnexa: user_pack_size) | integer | Additional statement pack size for the above additional statement fees | | custom | boolean | Default/Custom plan | | active | boolean | plan active status | |create_at| date_time |created date | |updated_at| date_time|updated date | Table Name: **site_custom_plan** ^ Column_name ^type ^ Description ^ | id | integer | primary key | | site_subscription_id | integer | Reference to site subscription table | | subscription_plan_id | integer | Reference to subscription plan table | Table Name: **site_subscriptions** ^ Column_name ^type ^ Description ^ | id | integer | primary key | | status | integer | (Can be TRIAL, TRIAL_EXPIRED, TRIAL_EXPIRED_DELETE, SUBSCRIBED, SUBSCRIPTION_CANCELED, SUBSCRIPTION_EXPIRED, SUBSCRIPTION_EXPIRED_DELETE) | | status_changed_at | datetime | datetime when the status field was updated | | status_change_notified | boolean | Indicates whether the site owner is notified about the recent status change or not | | start_at | datetime | When the subscription period starts | | end_at | datetime | When the subscription period ends | | next_renewal_at | datetime | When the subscription will be renewed. Usually based on subscription type | | preapproval_id | integer | Preapproval ID returned by wepay, used when charging the customer via a background job | | last_payment_id | integer | ID of corresponding payment record | | last_payment_status | string | (SUCCESS, FAILURE) | | subscription_plan_id | integer | The latest subscription plan of this company. Foreign key for subscription_plans | | subscription_period | string | The latest subscription period | | price | float | The latest subscription price | | statement_pack_size | integer | Total number of statement allowed for the subscription | | additional_per_statement_cost | float | Per statement cost for the overage statement| | additional_statement_pack_size | float | Additional/Overage statement pack size | | period_started_at | datetime | subscription started date | | previous_status | integer | Previous subscription status | | previous_subscription_plan_id | integer | reference id for previous subscription plan | | previous_status_start_at | datetime | Previous subscription start date | | previous_status_end_at | datetime | Previous subscription end date | | renew_billing_order_id | integer | reference id for previous subscription plan | | renew_subscription_plan_id | integer | reference id for previous subscription plan | | site_locked_type | string | Site locked Reason | | notified_type | integer | Last email notified type eg: trail reminder/expired, subscription renewal/expired | | retry_payment | boolean | Retry payment if the payment is failed true/false | | retry_at | datetime | Datetime to retry the subscription payment | | canceled_by_user_id | integer | User who canceled the subscription| | offline_payment | Boolean | Whether the site has enabled offline payment mode/online payment mode | | created_at | datetime | site subscription created date | | updated_at | datetime | site subscription updated date | Table Name: **site_orders** ^ Column_name ^type ^ Description ^ | id | integer | primary key | | site_subscription_id | integer | Reference to site subscription table | | subscription_plan_id | integer | Reference to subscription plan table | | payment_status | string | Set to SUCCESS if payment was successful and FAILURE otherwise. Initially the value can be NULL and later based on how the payment went through this can be set to SUCCESS or FAILURE | | discount | decimal | | | sub_total | decimal | | | total | decimal | | | description | string | | | reference_id | integer | | | pay_again | boolean | | | subscription_period | string | | | created_at | datetime | site order created date | | updated_at | datetime | site order updated date | Table Name: **site_order_items** ^ Column_name ^type ^ Description ^ | id | integer | primary key | |site_order_id | integer | | |item_type | String | Can by subscription, additional statement etc...Currently the value will be 'subscription' | |item_id| integer | | |price | Float | | |quantity | integer | | |created_at| datetime |created date | |updated_at| datetime |updated date | Table Name: **site_payments** ^ Column_name ^type ^ Description ^ | id | integer | primary key | |site_order_id| integer | Order for which this payment was made.| |ip_address| string | IP address of the payer | |payer_id | integer | site_subscrituion_id of the company who is paying | |status | string | SUCCESS or FAILURE | |amount | float | | |payment_method| string | Currently only WEPAY | |params| text | data that was passed to the gateway | |response| text | response that was returned by the gateway | |checkout_id | string | Checkout id | |payer_user_id| integer | Payee user id | |name_on_card| text | Name of the card holder | |refunded_at| datetime | Refunded date | |payment_redirected| boolean | payment redirected status | |error_code| string | payment error code | |created_at| datetime |created date | |updated_at| datetime |updated date | Table Name: **site_usages** Saves the statement details for each and every billing cycle at the end of the billing cycle. ^ Column_name ^type ^ Description ^ | id | integer | primary key | |site_subscription_id| integer | Foreign key to site_subscriptions table | |billing_period_start_time| datetime | When a given billing period starts. | |billing_period_end_time| datetime | When a given billing period ends. | |max_allowed_statement_count| integer| Maximum allowed statements count in the given billing period.| |statement_geneareted_count | integer | The actual statement in the billing period.| |created_at| datetime |created date | |updated_at| datetime |updated date | ===== Payment Gateway ===== Wepay payment gateway will be used for payment subscription similar to learnexa. ==== General flow of record creation ==== When company purchases subscription - Create a record in site_orders and site_order_items. At present the items for an order will always be 1 viz. subscription. Set payment_status = NIL - Generate the parameters that need to be sent to payment gateway and based on those parameters and the site_order_id create a record in site_payments table. Set 'status' column to NIL. After the response from the gateway is received, update the 'response' column of site_payments and based on the success or failure update the 'status' column. Also update the payment_status column in site_orders table to proper value i.e. success or failure. - Also if payment was successful then update the site_subscriptions table with proper status, preapproval_id and last_payment_id and last_payment_status ==== Enable/Disable site subscription ==== - Similar to learnexa - Enabled - When the site subscription is enabled subsite admin has to subscribe before the trail period expires inorder to use the site, Default option Enabled - Disable - When the site subscription is disabled, subscription status will be active and the site has no more payment required, site can be used as it's ==== Online payment ==== - Similar to learnexa ==== Offline Payment ==== Offline Payment process - Offline Payment mode option will be listed to each subsite under site subscription page - Super admin can set the offline payment to any subsite, If it set's true the normal "subscribe now" notification bar and the payment flow will not be shown to the subsite - Email will be sent to the subsite admin from super admin via backdoor with the required details and the payment will be done through offline - Once the payment is received super admin will have the option to mark 'payment received' to the site for the corresponded subscription period. - Site will not be suspended on overdue - Super admin will have option to view all the subsite billing history under site subscription - Super admin can cancel any subsite subscription from both offline/online payment mode ===== Disable/Hide site subscription ===== - We can disable the indivitual subsite site subscription from subscription settings or we have the backfill which will disable all the site subscription(bundle exec rake backfill:disable_all_existing_site_subscription) - We can completely hide the site subscription from super admin page by changing the settings in settings.yml(disable_site_subscription: true) - After this setting if we create new subsite those sites subscription will be automatically disabled by default ===== Open Queries ===== When the user upgrade the subscription in the middle of the subscription period, - Do we need to upgrade the subscription plan immediately or when the current subscription period ends? >> Uday: For now, this just works like learnexa, plan features are upgraded immediately but users are charged extra amounts only from next billing cycle. Will confirm this with Murali. \\ >> Murali: Correct - Please confirm the above offline payment process flow ===== Payment flow initial deployment preprocess steps ===== - Add delayed_job and rufus restart task in the deployment steps - Run all the Backfill task in server - configuration file changes in development.rb/staging.rb/production.rb - Add PUBLIC_URL constant **Backfill** a) bundle exec rake backfill:create_subscription_setting b) bundle exec rake backfill:populate_site_subscription_plans_default_values c) bundle exec rake backfill:create_site_subscription_for_default_company d) bundle exec rake backfill:create_site_subscription_for_existing_companies e) bundle exec rake backfill:create_or_update_supersite_wepay_account f) bundle exec rake backfill:disable_all_existing_site_subscription **Files to remove from svn track** a) public/javascripts/base_packaged.js b) public/stylesheets/application.css c) public/stylesheets/base_packaged.css d) public/stylesheets/client.css e) public/stylesheets/columns.css f) public/stylesheets/forms.css g) public/stylesheets/ie.css h) public/stylesheets/layers.css i) public/stylesheets/lightbox.css j) public/stylesheets/panels.css k) public/stylesheets/site_frame.css l) public/stylesheets/tabs.css m) public/stylesheets/tincan.css n) public/stylesheets/typography.css ===== Payment work flow screens ===== ==1. Subscription Settings== {{:1.subscription_settings.png?900x500|}} ==2. Subscription Plan== {{:2.subscription_plans.png?800x550|}} ==2a.Create Subscription Plan== {{:2a.create_subscription_plan.png?800x550|}} ==3. Site Subscription== {{:3.sub_sites_subscriptions.png?800x550|}} ==3a. Subsite settings with default online payment enabled== {{:3a.subsite_settings_default_online_payment_enabled.png?800x550|}} ==3b. Subsite subscription offline payment enabled== {{:3b.subsite_subscription_offline_payment_enabled.png?800x550|}} ==3c. Subsite billing history with offline payment== {{:3c.subsite_billing_history_with_offline_payment.png?800x550|}} ==3c1. Subsite billing history view for super admin== {{:3c.subsite_billing_info_view_for_super_admin.png?800x550|}} ==3d. Subsite billing info super admin with statement overage== {{:3d.subsite_billing_info_super_admin_with_statement_overage.png?800x550|}} ==3e. Billing history view for subsite admin== {{:3e.billing_history_view_for_subsite_admin.png?800x550|}} ==4. Pick up subscription plan for subsite== {{:4.pick_up_subscription_plan_for_subsite.png?800x550|}} ==4a. Subscribe form for subsite== {{:4a.subscribe_form_for_subsite.png?800x550|}} ==4b. Subscribe confirmation lightbox== {{:4b.subscribe_confirmation_lightbox.png?800x550|}}