Add support for 'event_discount.*' events
This commit is contained in:
parent
2893a2bf47
commit
e7c482bf3a
6 changed files with 315 additions and 72 deletions
|
@ -8,14 +8,7 @@ class EventDiscountsController < ApplicationController
|
||||||
before_action :authenticate_event_editor!, except: [:index]
|
before_action :authenticate_event_editor!, except: [:index]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
event_discount_params[:event_id] = current_event.id
|
render json: { data: {event_discount: current_event.event_discounts.create(event_discount_params[:event_discount]) } }
|
||||||
|
|
||||||
render JsonResp.new(event_discount_params) do |_data|
|
|
||||||
requires(:code, :name).as_string
|
|
||||||
requires(:event_id, :percent).as_int
|
|
||||||
end.when_valid do |data|
|
|
||||||
{ status: 200, json: { event_discount: current_event.event_discounts.create(data) } }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -23,27 +16,22 @@ class EventDiscountsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
discount = Hamster.to_ruby(
|
|
||||||
Psql.execute(
|
current_event_discount.update event_discount_params[:event_discount]
|
||||||
Qexpr.new.update(:event_discounts, event_discount_params)
|
render json: { status: 200, data: current_event_discount }
|
||||||
.where('id=$id', id: params[:id])
|
|
||||||
.returning('*')
|
|
||||||
).first
|
|
||||||
)
|
|
||||||
render json: { status: 200, data: discount }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
Psql.execute(
|
current_event_discount.destroy
|
||||||
Qexpr.new.delete_from('event_discounts')
|
|
||||||
.where('event_discounts.event_id=$id', id: params['event_id'])
|
|
||||||
.where('event_discounts.id=$id', id: params['id'])
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def current_event_discount
|
||||||
|
current_event.event_discounts.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
def event_discount_params
|
def event_discount_params
|
||||||
params.required(:event_discount).permit(:code, :event_id, :name, :percent)
|
params.required(:event_discount).permit(:code, :name, :percent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,19 +7,77 @@ class EventDiscount < ApplicationRecord
|
||||||
# :event_id,
|
# :event_id,
|
||||||
# :name,
|
# :name,
|
||||||
# :percent
|
# :percent
|
||||||
|
validates :name, presence: true
|
||||||
|
validates :code, presence: true
|
||||||
|
validates :event, presence: true
|
||||||
|
validates :percent, presence: true, numericality: {only_integer: true, greater_than: 0, less_than_or_equal_to: 100}
|
||||||
|
|
||||||
|
|
||||||
|
# we use after_create_commit because the db could be in an inconsistent state and the messages will be slightly wrong
|
||||||
|
# we use after commit on the rest for consistency
|
||||||
|
after_create_commit :publish_create
|
||||||
|
after_destroy_commit :publish_delete
|
||||||
|
after_update_commit :publish_updated
|
||||||
|
|
||||||
belongs_to :event
|
belongs_to :event
|
||||||
has_many :tickets
|
has_many :tickets
|
||||||
|
|
||||||
def to_builder(*expand)
|
def to_builder(*expand)
|
||||||
Jbuilder.new do |json|
|
Jbuilder.new do |json|
|
||||||
json.(self, :id, :name)
|
json.(self, :id, :name, :code)
|
||||||
|
json.deleted !persisted?
|
||||||
|
json.object 'event_discount'
|
||||||
|
json.discount do
|
||||||
|
json.percent percent
|
||||||
|
end
|
||||||
|
|
||||||
if event
|
if event
|
||||||
if expand.include? :event
|
if expand.include? :event
|
||||||
json.event event.to_builder
|
json.event event.to_builder
|
||||||
else
|
else
|
||||||
json.event event.id
|
json.event event.id
|
||||||
end
|
end
|
||||||
|
if event.nonprofit
|
||||||
|
if expand.include? :nonprofit
|
||||||
|
json.nonprofit event.nonprofit.to_builder
|
||||||
|
else
|
||||||
|
json.nonprofit event.nonprofit.id
|
||||||
|
end
|
||||||
|
else
|
||||||
|
json.nonprofit nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if expand.include? :ticket_levels
|
||||||
|
json.ticket_levels event.ticket_levels do |tl|
|
||||||
|
json.merge! tl.to_builder.attributes!
|
||||||
|
end
|
||||||
|
else
|
||||||
|
json.ticket_levels event.ticket_levels.pluck(:id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def publish_create
|
||||||
|
Houdini.event_publisher.announce(:event_discount_created, to_event('event_discount.created', :event, :nonprofit, :ticket_levels).attributes!)
|
||||||
|
end
|
||||||
|
|
||||||
|
def publish_updated
|
||||||
|
Houdini.event_publisher.announce(:event_discount_updated, to_event('event_discount.updated', :event, :nonprofit, :ticket_levels).attributes!)
|
||||||
|
end
|
||||||
|
|
||||||
|
def publish_delete
|
||||||
|
Houdini.event_publisher.announce(:event_discount_deleted, to_event('event_discount.deleted', :event, :nonprofit, :ticket_levels).attributes!)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_event(event_type, *expand)
|
||||||
|
Jbuilder.new do |event|
|
||||||
|
event.id SecureRandom.uuid
|
||||||
|
event.object 'object_event'
|
||||||
|
event.type event_type
|
||||||
|
event.data do
|
||||||
|
event.object to_builder(*expand)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -73,7 +73,7 @@ class TicketLevel < ApplicationRecord
|
||||||
|
|
||||||
if expand.include? :event_discounts
|
if expand.include? :event_discounts
|
||||||
json.event_discounts event.event_discounts do |disc|
|
json.event_discounts event.event_discounts do |disc|
|
||||||
disc.to_builder
|
json.merge! disc.to_builder.attributes!
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
json.event_discounts event.event_discounts.pluck(:id)
|
json.event_discounts event.event_discounts.pluck(:id)
|
||||||
|
@ -84,18 +84,18 @@ class TicketLevel < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
def publish_create
|
def publish_create
|
||||||
Houdini.event_publisher.announce(:ticket_level_created, to_event('ticket_level.created', :event, :nonprofit).attributes!)
|
Houdini.event_publisher.announce(:ticket_level_created, to_event('ticket_level.created', :event, :nonprofit, :event_discounts).attributes!)
|
||||||
end
|
end
|
||||||
|
|
||||||
def publish_updated
|
def publish_updated
|
||||||
# we don't run update when we've really just discarded
|
# we don't run update when we've really just discarded
|
||||||
unless deleted
|
unless deleted
|
||||||
Houdini.event_publisher.announce(:ticket_level_updated, to_event('ticket_level.updated', :event, :nonprofit).attributes!)
|
Houdini.event_publisher.announce(:ticket_level_updated, to_event('ticket_level.updated', :event, :nonprofit, :event_discounts).attributes!)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def publish_delete
|
def publish_delete
|
||||||
Houdini.event_publisher.announce(:ticket_level_deleted, to_event('ticket_level.deleted', :event, :nonprofit).attributes!)
|
Houdini.event_publisher.announce(:ticket_level_deleted, to_event('ticket_level.deleted', :event, :nonprofit, :event_discounts).attributes!)
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_event(event_type, *expand)
|
def to_event(event_type, *expand)
|
||||||
|
|
|
@ -1,15 +1,23 @@
|
||||||
// License: LGPL-3.0-or-later
|
// License: LGPL-3.0-or-later
|
||||||
import type { IdType, HoudiniObject } from '../../common';
|
import type { IdType, HoudiniObject, Amount, HoudiniEvent } from '../../common';
|
||||||
import type Nonprofit from '..';
|
import type Nonprofit from '..';
|
||||||
import type Event from '.';
|
import type Event from '.';
|
||||||
import type { TicketLevel } from './TicketLevel';
|
import type { TicketLevel } from './TicketLevel';
|
||||||
|
|
||||||
|
|
||||||
|
type DiscountType = { percent: number } | { amount: Amount };
|
||||||
/**
|
/**
|
||||||
* Describes an EventDiscount (shell)
|
* Describes an EventDiscount (shell)
|
||||||
*/
|
*/
|
||||||
export interface EventDiscount extends HoudiniObject {
|
export interface EventDiscount extends HoudiniObject {
|
||||||
|
code: string;
|
||||||
|
discount: DiscountType;
|
||||||
event: IdType | Event;
|
event: IdType | Event;
|
||||||
nonprofit: IdType | Nonprofit;
|
nonprofit: IdType | Nonprofit;
|
||||||
object: "event_discount";
|
object: "event_discount";
|
||||||
ticket_levels: IdType[] | TicketLevel[];
|
ticket_levels: IdType[] | TicketLevel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EventDiscountCreated = HoudiniEvent<'event_discount.created', EventDiscount>;
|
||||||
|
export type EventDiscountlUpdated = HoudiniEvent<'event_discount.updated', EventDiscount>;
|
||||||
|
export type EventDiscountDeleted = HoudiniEvent<'event_discount.deleted', EventDiscount>;
|
232
spec/models/event_discount_spec.rb
Normal file
232
spec/models/event_discount_spec.rb
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe EventDiscount, type: :model do
|
||||||
|
include_context :shared_donation_charge_context
|
||||||
|
let(:name) {"CUSTOM EVENT DISCOUNT"}
|
||||||
|
let(:percent) { 55}
|
||||||
|
let(:code) { "fewet"}
|
||||||
|
let(:event_discount) {
|
||||||
|
ticket_level
|
||||||
|
event.event_discounts.create(name: name, percent: percent, code: code)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe 'validate' do
|
||||||
|
let(:event_discount) { ed = EventDiscount.new; ed.save; ed}
|
||||||
|
let(:ed_percent_at_0) { ed = EventDiscount.new(percent: 0); ed.save; ed}
|
||||||
|
let(:ed_percent_at_101) { ed = EventDiscount.new(percent: 101); ed.save; ed}
|
||||||
|
|
||||||
|
it('has errors on name') do
|
||||||
|
expect(event_discount.errors.details[:name].length).to be(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('has errors on code') do
|
||||||
|
expect(event_discount.errors.details[:code].length).to be(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('has errors on event') do
|
||||||
|
expect(event_discount.errors.details[:event].length).to be(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('has errors on percent') do
|
||||||
|
expect(event_discount.errors.details[:percent].length).to be(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('has errors on percents at 0') do
|
||||||
|
expect(ed_percent_at_0.errors.details[:percent].length).to be(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('has errors on percents at 101') do
|
||||||
|
expect(ed_percent_at_101.errors.details[:percent].length).to be(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'create' do
|
||||||
|
|
||||||
|
it 'is without error' do
|
||||||
|
expect(event_discount.errors).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'announces create' do
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:ticket_level_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:event_discount_created, {
|
||||||
|
'id' => kind_of(String),
|
||||||
|
'object' => 'object_event',
|
||||||
|
'type' => 'event_discount.created',
|
||||||
|
'data' => {
|
||||||
|
'object' => {
|
||||||
|
'code' => code,
|
||||||
|
'deleted' => false,
|
||||||
|
'discount' => {
|
||||||
|
'percent' => percent
|
||||||
|
},
|
||||||
|
'event' => {
|
||||||
|
'id' => event.id,
|
||||||
|
'name' => event.name,
|
||||||
|
'object' => 'event',
|
||||||
|
'nonprofit' => nonprofit.id
|
||||||
|
},
|
||||||
|
'id'=> kind_of(Numeric),
|
||||||
|
'name' => name,
|
||||||
|
'nonprofit'=> {
|
||||||
|
'id' => nonprofit.id,
|
||||||
|
'name' => nonprofit.name,
|
||||||
|
'object' => 'nonprofit'
|
||||||
|
},
|
||||||
|
'object' => 'event_discount',
|
||||||
|
'ticket_levels' => [
|
||||||
|
{
|
||||||
|
'id' => ticket_level.id,
|
||||||
|
'name' => ticket_level.name,
|
||||||
|
'deleted' => ticket_level.deleted,
|
||||||
|
'order' => ticket_level.order,
|
||||||
|
'limit' => ticket_level.limit,
|
||||||
|
'object' => 'ticket_level',
|
||||||
|
'description' => ticket_level.description,
|
||||||
|
'amount' => {
|
||||||
|
'value_in_cents' => ticket_level.amount,
|
||||||
|
'currency' => 'usd'
|
||||||
|
},
|
||||||
|
'available_to' => 'everyone',
|
||||||
|
'nonprofit' => nonprofit.id,
|
||||||
|
'event' => event.id,
|
||||||
|
'event_discounts' => [kind_of(Numeric)]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
event_discount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'update' do
|
||||||
|
it 'is without error' do
|
||||||
|
event_discount.code = 'code'
|
||||||
|
event_discount.save
|
||||||
|
expect(event_discount.errors).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'announces updated' do
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:ticket_level_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:event_discount_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:event_discount_updated, {
|
||||||
|
'id' => kind_of(String),
|
||||||
|
'object' => 'object_event',
|
||||||
|
'type' => 'event_discount.updated',
|
||||||
|
'data' => {
|
||||||
|
'object' => {
|
||||||
|
'code' => 'code',
|
||||||
|
'deleted' => false,
|
||||||
|
'discount' => {
|
||||||
|
'percent' => percent
|
||||||
|
},
|
||||||
|
'event' => {
|
||||||
|
'id' => event.id,
|
||||||
|
'name' => event.name,
|
||||||
|
'object' => 'event',
|
||||||
|
'nonprofit' => nonprofit.id
|
||||||
|
},
|
||||||
|
'id'=> kind_of(Numeric),
|
||||||
|
'name' => name,
|
||||||
|
'nonprofit'=> {
|
||||||
|
'id' => nonprofit.id,
|
||||||
|
'name' => nonprofit.name,
|
||||||
|
'object' => 'nonprofit'
|
||||||
|
},
|
||||||
|
'object' => 'event_discount',
|
||||||
|
'ticket_levels' => [
|
||||||
|
{
|
||||||
|
'id' => ticket_level.id,
|
||||||
|
'name' => ticket_level.name,
|
||||||
|
'deleted' => ticket_level.deleted,
|
||||||
|
'order' => ticket_level.order,
|
||||||
|
'limit' => ticket_level.limit,
|
||||||
|
'object' => 'ticket_level',
|
||||||
|
'description' => ticket_level.description,
|
||||||
|
'amount' => {
|
||||||
|
'value_in_cents' => ticket_level.amount,
|
||||||
|
'currency' => 'usd'
|
||||||
|
},
|
||||||
|
'available_to' => 'everyone',
|
||||||
|
'nonprofit' => nonprofit.id,
|
||||||
|
'event' => event.id,
|
||||||
|
'event_discounts' => [kind_of(Numeric)]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).ordered
|
||||||
|
|
||||||
|
event_discount.code = 'code'
|
||||||
|
event_discount.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe 'deleted' do
|
||||||
|
it 'is without error' do
|
||||||
|
event_discount.destroy
|
||||||
|
expect(event_discount).to_not be_persisted
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'announces deleted' do
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:ticket_level_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:event_discount_created, anything).ordered
|
||||||
|
expect(Houdini.event_publisher).to receive(:announce).with(:event_discount_deleted, {
|
||||||
|
'id' => kind_of(String),
|
||||||
|
'object' => 'object_event',
|
||||||
|
'type' => 'event_discount.deleted',
|
||||||
|
'data' => {
|
||||||
|
'object' => {
|
||||||
|
'code' => code,
|
||||||
|
'deleted' => true,
|
||||||
|
'discount' => {
|
||||||
|
'percent' => percent
|
||||||
|
},
|
||||||
|
'event' => {
|
||||||
|
'id' => event.id,
|
||||||
|
'name' => event.name,
|
||||||
|
'object' => 'event',
|
||||||
|
'nonprofit' => nonprofit.id
|
||||||
|
},
|
||||||
|
'id'=> kind_of(Numeric),
|
||||||
|
'name' => name,
|
||||||
|
'nonprofit'=> {
|
||||||
|
'id' => nonprofit.id,
|
||||||
|
'name' => nonprofit.name,
|
||||||
|
'object' => 'nonprofit'
|
||||||
|
},
|
||||||
|
'object' => 'event_discount',
|
||||||
|
'ticket_levels' => [
|
||||||
|
{
|
||||||
|
'id' => ticket_level.id,
|
||||||
|
'name' => ticket_level.name,
|
||||||
|
'deleted' => ticket_level.deleted,
|
||||||
|
'order' => ticket_level.order,
|
||||||
|
'limit' => ticket_level.limit,
|
||||||
|
'object' => 'ticket_level',
|
||||||
|
'description' => ticket_level.description,
|
||||||
|
'amount' => {
|
||||||
|
'value_in_cents' => ticket_level.amount,
|
||||||
|
'currency' => 'usd'
|
||||||
|
},
|
||||||
|
'available_to' => 'everyone',
|
||||||
|
'nonprofit' => nonprofit.id,
|
||||||
|
'event' => event.id,
|
||||||
|
'event_discounts' => [kind_of(Numeric)]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).ordered
|
||||||
|
|
||||||
|
event_discount.destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -302,47 +302,4 @@ RSpec.describe TicketLevel, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# it 'creates' do
|
|
||||||
# expect(tag_master.errors).to be_empty
|
|
||||||
# end
|
|
||||||
|
|
||||||
# it 'announces create' do
|
|
||||||
# expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_created, {
|
|
||||||
# 'id' => kind_of(String),
|
|
||||||
# 'object' => 'event',
|
|
||||||
# 'type' => 'tag_master.created',
|
|
||||||
# 'data' => {
|
|
||||||
# 'object' => {
|
|
||||||
# 'id'=> kind_of(Numeric),
|
|
||||||
# 'deleted' => false,
|
|
||||||
# 'name' => name,
|
|
||||||
# 'nonprofit'=> nonprofit.id,
|
|
||||||
# 'object' => 'tag_master'
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# })
|
|
||||||
|
|
||||||
# tag_master
|
|
||||||
# end
|
|
||||||
|
|
||||||
# it 'announces deleted' do
|
|
||||||
# expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_created, anything).ordered
|
|
||||||
# expect(Houdini.event_publisher).to receive(:announce).with(:tag_master_deleted, {
|
|
||||||
# 'id' => kind_of(String),
|
|
||||||
# 'object' => 'event',
|
|
||||||
# 'type' => 'tag_master.deleted',
|
|
||||||
# 'data' => {
|
|
||||||
# 'object' => {
|
|
||||||
# 'id'=> kind_of(Numeric),
|
|
||||||
# 'deleted' => true,
|
|
||||||
# 'name' => name,
|
|
||||||
# 'nonprofit'=> nonprofit.id,
|
|
||||||
# 'object' => 'tag_master'
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# }).ordered
|
|
||||||
|
|
||||||
# tag_master.discard!
|
|
||||||
|
|
||||||
# end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue