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]
|
||||
|
||||
def create
|
||||
event_discount_params[:event_id] = current_event.id
|
||||
|
||||
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
|
||||
render json: { data: {event_discount: current_event.event_discounts.create(event_discount_params[:event_discount]) } }
|
||||
end
|
||||
|
||||
def index
|
||||
|
@ -23,27 +16,22 @@ class EventDiscountsController < ApplicationController
|
|||
end
|
||||
|
||||
def update
|
||||
discount = Hamster.to_ruby(
|
||||
Psql.execute(
|
||||
Qexpr.new.update(:event_discounts, event_discount_params)
|
||||
.where('id=$id', id: params[:id])
|
||||
.returning('*')
|
||||
).first
|
||||
)
|
||||
render json: { status: 200, data: discount }
|
||||
|
||||
current_event_discount.update event_discount_params[:event_discount]
|
||||
render json: { status: 200, data: current_event_discount }
|
||||
end
|
||||
|
||||
def destroy
|
||||
Psql.execute(
|
||||
Qexpr.new.delete_from('event_discounts')
|
||||
.where('event_discounts.event_id=$id', id: params['event_id'])
|
||||
.where('event_discounts.id=$id', id: params['id'])
|
||||
)
|
||||
current_event_discount.destroy
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_event_discount
|
||||
current_event.event_discounts.find(params[:id])
|
||||
end
|
||||
|
||||
def event_discount_params
|
||||
params.required(:event_discount).permit(:code, :event_id, :name, :percent)
|
||||
params.required(:event_discount).permit(:code, :name, :percent)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,19 +7,77 @@ class EventDiscount < ApplicationRecord
|
|||
# :event_id,
|
||||
# :name,
|
||||
# :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
|
||||
has_many :tickets
|
||||
|
||||
def to_builder(*expand)
|
||||
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 expand.include? :event
|
||||
json.event event.to_builder
|
||||
else
|
||||
json.event event.id
|
||||
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
|
||||
|
|
|
@ -73,7 +73,7 @@ class TicketLevel < ApplicationRecord
|
|||
|
||||
if expand.include? :event_discounts
|
||||
json.event_discounts event.event_discounts do |disc|
|
||||
disc.to_builder
|
||||
json.merge! disc.to_builder.attributes!
|
||||
end
|
||||
else
|
||||
json.event_discounts event.event_discounts.pluck(:id)
|
||||
|
@ -84,18 +84,18 @@ class TicketLevel < ApplicationRecord
|
|||
|
||||
private
|
||||
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
|
||||
|
||||
def publish_updated
|
||||
# we don't run update when we've really just discarded
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
def to_event(event_type, *expand)
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
// 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 Event from '.';
|
||||
import type { TicketLevel } from './TicketLevel';
|
||||
|
||||
|
||||
type DiscountType = { percent: number } | { amount: Amount };
|
||||
/**
|
||||
* Describes an EventDiscount (shell)
|
||||
*/
|
||||
export interface EventDiscount extends HoudiniObject {
|
||||
code: string;
|
||||
discount: DiscountType;
|
||||
event: IdType | Event;
|
||||
nonprofit: IdType | Nonprofit;
|
||||
object: "event_discount";
|
||||
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
|
||||
# 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
|
||||
|
|
Loading…
Reference in a new issue