mirror of
https://github.com/System-End/theseus.git
synced 2026-04-19 23:32:49 +00:00
warehouse api!
This commit is contained in:
parent
0654801c52
commit
911c6787e0
13 changed files with 211 additions and 35 deletions
|
|
@ -27,6 +27,10 @@ module API
|
|||
render json: { error: "idempotency_error", messages: ["a record by that idempotency key already exists!"] }, status: :bad_request
|
||||
end
|
||||
|
||||
rescue_from ActionController::ParameterMissing do |e|
|
||||
render json: { error: "missing_parameter", messages: [e.message] }, status: :bad_request
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_expand
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
module API
|
||||
module V1
|
||||
class LetterQueuesController < ApplicationController
|
||||
include AddressParameterParsing
|
||||
|
||||
before_action :set_letter_queue, only: [:show, :create_letter]
|
||||
before_action :set_instant_letter_queue, only: [:create_instant_letter, :queued]
|
||||
|
||||
|
|
@ -36,18 +38,8 @@ module API
|
|||
def create_letter
|
||||
authorize @letter_queue
|
||||
|
||||
# Normalize country name using FrickinCountryNames
|
||||
country = FrickinCountryNames.find_country(letter_params[:address][:country])
|
||||
if country.nil?
|
||||
render json: { error: "couldn't figure out country name #{letter_params[:address][:country]}" }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
# Create address with normalized country
|
||||
address_params = letter_params[:address].merge(country: country.alpha2)
|
||||
# Normalize state name to abbreviation
|
||||
address_params[:state] = FrickinCountryNames.normalize_state(country, address_params[:state])
|
||||
addy = Address.new(address_params)
|
||||
addy = parse_address_from_params(letter_params[:address])
|
||||
return unless addy
|
||||
|
||||
@letter = @letter_queue.create_letter!(
|
||||
addy,
|
||||
|
|
@ -62,18 +54,8 @@ module API
|
|||
def create_instant_letter
|
||||
authorize @letter_queue, policy_class: Letter::QueuePolicy
|
||||
|
||||
# Normalize country name using FrickinCountryNames
|
||||
country = FrickinCountryNames.find_country(letter_params[:address][:country])
|
||||
if country.nil?
|
||||
render json: { error: "couldn't figure out country name #{letter_params[:address][:country]}" }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
# Create address with normalized country
|
||||
address_params = letter_params[:address].merge(country: country.alpha2)
|
||||
# Normalize state name to abbreviation
|
||||
address_params[:state] = FrickinCountryNames.normalize_state(country, address_params[:state])
|
||||
addy = Address.new(address_params)
|
||||
addy = parse_address_from_params(letter_params[:address])
|
||||
return unless addy
|
||||
|
||||
@letter = @letter_queue.process_letter_instantly!(
|
||||
addy,
|
||||
|
|
@ -118,11 +100,6 @@ module API
|
|||
],
|
||||
)
|
||||
end
|
||||
|
||||
def normalize_country(country)
|
||||
return "US" if country.blank? || country.downcase == "usa" || country.downcase == "united states"
|
||||
country
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
111
app/controllers/api/v1/warehouse_orders_controller.rb
Normal file
111
app/controllers/api/v1/warehouse_orders_controller.rb
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
module API
|
||||
module V1
|
||||
class WarehouseOrdersController < ApplicationController
|
||||
include AddressParameterParsing
|
||||
|
||||
before_action :set_warehouse_order, only: [:show]
|
||||
|
||||
rescue_from ActiveRecord::RecordNotFound do |e|
|
||||
render json: { error: "Warehouse order not found" }, status: :not_found
|
||||
end
|
||||
|
||||
rescue_from ActiveRecord::RecordInvalid do |e|
|
||||
Honeybadger.notify(e)
|
||||
render json: {
|
||||
error: "Validation failed",
|
||||
details: e.record.errors.full_messages,
|
||||
}, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def show
|
||||
authorize @warehouse_order
|
||||
end
|
||||
|
||||
def index
|
||||
@warehouse_orders = policy_scope(Warehouse::Order)
|
||||
end
|
||||
|
||||
def from_template
|
||||
@template = Warehouse::Template.find_by_public_id!(params[:template_id])
|
||||
address = parse_address_from_params(permit_address_params)
|
||||
@warehouse_order = Warehouse::Order.from_template(@template, warehouse_order_params.merge(address:, user: current_user))
|
||||
authorize @warehouse_order
|
||||
|
||||
# Build additional line items from contents if provided
|
||||
if params[:contents].present?
|
||||
contents_params.each do |content_item|
|
||||
sku = Warehouse::SKU.find_by(sku: content_item[:sku])
|
||||
unless sku
|
||||
render json: { error: "SKU not found: #{content_item[:sku]}" }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
@warehouse_order.line_items.build(
|
||||
sku: sku,
|
||||
quantity: content_item[:quantity],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
address.save!
|
||||
@warehouse_order.save!
|
||||
@warehouse_order.dispatch!
|
||||
render :show, status: :created
|
||||
end
|
||||
|
||||
def create
|
||||
address = parse_address_from_params(permit_address_params)
|
||||
@warehouse_order = Warehouse::Order.new(warehouse_order_params.merge(address:, user: current_user, source_tag: SourceTag.first))
|
||||
authorize @warehouse_order
|
||||
address.save!
|
||||
|
||||
# Build line items from contents
|
||||
contents_params.each do |content_item|
|
||||
sku = Warehouse::SKU.find_by(sku: content_item[:sku])
|
||||
unless sku
|
||||
render json: { error: "SKU not found: #{content_item[:sku]}" }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
@warehouse_order.line_items.build(
|
||||
sku: sku,
|
||||
quantity: content_item[:quantity],
|
||||
)
|
||||
end
|
||||
|
||||
@warehouse_order.save!
|
||||
@warehouse_order.dispatch!
|
||||
render :show, status: :created
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_warehouse_order
|
||||
@warehouse_order = policy_scope(Warehouse::Order).find_by!(hc_id: params[:id])
|
||||
end
|
||||
|
||||
def warehouse_order_params
|
||||
params.require(:warehouse_order).permit(
|
||||
:recipient_email,
|
||||
:user_facing_title,
|
||||
:idempotency_key,
|
||||
metadata: {},
|
||||
tags: [],
|
||||
).tap do |wp|
|
||||
wp.require(:recipient_email)
|
||||
wp.require(:tags)
|
||||
raise ActionController::ParameterMissing.new(:tags) if wp[:tags].blank? || wp[:tags].empty?
|
||||
end
|
||||
end
|
||||
|
||||
def contents_params
|
||||
return [] unless params[:contents].present?
|
||||
|
||||
params.expect(contents: [[:sku, :quantity]]).map.with_index do |content_item, index|
|
||||
content_item.tap do |cp|
|
||||
raise ActionController::ParameterMissing.new([:contents, index, :sku]) unless cp[:sku].present?
|
||||
raise ActionController::ParameterMissing.new([:contents, index, :quantity]) unless cp[:quantity].present?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
38
app/controllers/concerns/address_parameter_parsing.rb
Normal file
38
app/controllers/concerns/address_parameter_parsing.rb
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
module AddressParameterParsing
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def parse_address_from_params(address_params)
|
||||
return nil if address_params.blank?
|
||||
|
||||
Address.new(address_params).validate!
|
||||
|
||||
# Normalize country name using FrickinCountryNames
|
||||
country = FrickinCountryNames.find_country(address_params[:country])
|
||||
if country.nil?
|
||||
render json: { error: "couldn't figure out country name #{address_params[:country]}" }, status: :unprocessable_entity
|
||||
return nil
|
||||
end
|
||||
|
||||
# Create address with normalized country
|
||||
normalized_address_params = address_params.merge(country: country.alpha2)
|
||||
# Normalize state name to abbreviation
|
||||
normalized_address_params[:state] = FrickinCountryNames.normalize_state(country, normalized_address_params[:state])
|
||||
|
||||
Address.new(normalized_address_params)
|
||||
end
|
||||
|
||||
def permit_address_params
|
||||
params.require(:address).permit(
|
||||
:first_name,
|
||||
:last_name,
|
||||
:line_1,
|
||||
:line_2,
|
||||
:city,
|
||||
:state,
|
||||
:postal_code,
|
||||
:country
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -22,6 +22,10 @@
|
|||
#
|
||||
class Warehouse::Template < ApplicationRecord
|
||||
include HasWarehouseLineItems
|
||||
include PublicIdentifiable
|
||||
|
||||
set_public_id_prefix "wot"
|
||||
|
||||
scope :shared, -> { where(public: true) }
|
||||
|
||||
belongs_to :user
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ class Warehouse::OrderPolicy < ApplicationPolicy
|
|||
user_can_warehouse
|
||||
end
|
||||
|
||||
alias_method :from_template?, :create?
|
||||
|
||||
def edit?
|
||||
return false unless user_can_warehouse
|
||||
record_belongs_to_user || user_is_admin
|
||||
|
|
|
|||
18
app/views/api/v1/warehouse/orders/_order.json.jb
Normal file
18
app/views/api/v1/warehouse/orders/_order.json.jb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
id: order.hc_id,
|
||||
status: order.aasm_state,
|
||||
tags: order.tags,
|
||||
address: render(order.address),
|
||||
metadata: order.metadata || {},
|
||||
recipient_email: order.recipient_email,
|
||||
dispatched_at: order.dispatched_at,
|
||||
mailed_at: order.mailed_at,
|
||||
tracking_number: order.tracking_number,
|
||||
carrier: order.carrier,
|
||||
service: order.service,
|
||||
weight: order.weight,
|
||||
contents_cost: order.contents_cost,
|
||||
labor_cost: order.labor_cost,
|
||||
postage_cost: order.postage_cost,
|
||||
idempotency_key: order.idempotency_key,
|
||||
}.compact_blank
|
||||
3
app/views/api/v1/warehouse_orders/index.json.jb
Normal file
3
app/views/api/v1/warehouse_orders/index.json.jb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
warehouse_orders: @warehouse_orders.map { |o| render o },
|
||||
}
|
||||
3
app/views/api/v1/warehouse_orders/show.json.jb
Normal file
3
app/views/api/v1/warehouse_orders/show.json.jb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
warehouse_order: render(@warehouse_order),
|
||||
}
|
||||
|
|
@ -9,10 +9,13 @@
|
|||
<%= render 'shared/user_mention', user: template.user %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<small class="text-muted">Contents:</small>
|
||||
<%= render 'warehouse/orders/line_items', order: template %>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<small class="text-muted">API ID:</small>
|
||||
<%= template.public_id %>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
|
|
|||
|
|
@ -682,6 +682,11 @@ Rails.application.routes.draw do
|
|||
get :letters
|
||||
end
|
||||
end
|
||||
resources :warehouse_orders, only: [:show, :index, :create] do
|
||||
collection do
|
||||
post "from_template/:template_id", to: "warehouse_orders#from_template", as: :from_template
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
10
db/seeds.rb
10
db/seeds.rb
|
|
@ -10,10 +10,10 @@
|
|||
SourceTag.find_or_create_by!(
|
||||
name: "Theseus web interface",
|
||||
slug: "theseus_web",
|
||||
owner: "Nora"
|
||||
owner: "Nora",
|
||||
)
|
||||
|
||||
Warehouse::PurposeCode.find_or_create_by!(
|
||||
code: Rails.env.production? ? 'HQ' : 'HQ-dev',
|
||||
description: 'general HQ mailing'
|
||||
)
|
||||
# Warehouse::PurposeCode.find_or_create_by!(
|
||||
# code: Rails.env.production? ? 'HQ' : 'HQ-dev',
|
||||
# description: 'general HQ mailing'
|
||||
# )
|
||||
|
|
|
|||
8
lib/tasks/annotate_rb.rake
Normal file
8
lib/tasks/annotate_rb.rake
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# This rake task was added by annotate_rb gem.
|
||||
|
||||
# Can set `ANNOTATERB_SKIP_ON_DB_TASKS` to be anything to skip this
|
||||
if Rails.env.development? && ENV["ANNOTATERB_SKIP_ON_DB_TASKS"].nil?
|
||||
require "annotate_rb"
|
||||
|
||||
AnnotateRb::Core.load_rake_tasks
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue