Backoffice customer, Add pop up to list customer payments

This commit is contained in:
Gaetan Craig-Riou
2026-01-30 12:42:16 +11:00
parent 6aa4bf7a33
commit fec5516fce
8 changed files with 129 additions and 11 deletions

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module Admin
class CustomerAccountTransactionController < Admin::ResourceController
def index
@available_credit = @collection.first.balance
respond_with do |format|
format.turbo_stream {
render :index
}
end
end
# We are using an old version of CanCanCan so I could not get `accessible_by` to work properly,
# so we are doing our own authorization before calling 'accessible_by'
def collection
allowed_customers = OpenFoodNetwork::Permissions.new(spree_current_user)
.managed_enterprises.joins(:customers).select("customers.id").map(&:id)
raise CanCan::AccessDenied unless allowed_customers.include?(params[:customer_id].to_i)
CustomerAccountTransaction.accessible_by(current_ability, action)
.where(customer_id: params[:customer_id]).order(id: :desc)
end
end
end

View File

@@ -61,7 +61,7 @@ module Spree
add_manage_line_items_abilities user
end
add_relationship_management_abilities user if can_manage_relationships? user
add_customer_payment_abilities user if can_manage_enterprises? user
add_customer_account_transaction_abilities user if can_manage_enterprises? user
end
# New users have no enterprises.
@@ -459,8 +459,8 @@ module Spree
end
end
def add_customer_payment_abilities(_user)
can [:create], CustomerAccountTransaction
def add_customer_account_transaction_abilities(_user)
can [:admin, :create, :index], CustomerAccountTransaction
end
end
end

View File

@@ -7,7 +7,7 @@ module Api
# columns to instance methods. This way, the `balance_value` alias on that class ends up being
# `object.balance_value` here.
class CustomerWithBalanceSerializer < CustomerSerializer
attributes :balance, :balance_status, :available_credit
attributes :balance, :balance_status, :available_credit, :available_credit_url
delegate :balance_value, :credit_value, to: :object
@@ -15,10 +15,6 @@ module Api
Spree::Money.new(balance_value, currency: CurrentConfig.get(:currency)).to_s
end
def available_credit
Spree::Money.new(object.credit_value).to_s
end
def balance_status
if balance_value.positive?
"credit_owed"
@@ -28,6 +24,14 @@ module Api
""
end
end
def available_credit
Spree::Money.new(object.credit_value).to_s
end
def available_credit_url
admin_customer_customer_account_transaction_index_path(object.id)
end
end
end
end

View File

@@ -0,0 +1,31 @@
= turbo_stream.update "customer-account-transactions-modal-container" do
= render ModalComponent.new(id: "customer-account-transactions-modal", instant: true, modal_class: "big") do
%h3
= t(".available_credit", available_credit: Spree::Money.new(@available_credit))
%table.index
%thead
%tr
%th.transaction-date
= t(".transaction_date")
%th.description
= t(".description")
%th.payment-method
= t(".payment_method")
%th.amount
= t(".amount")
%th.running-balance
= t(".running_balance")
%tbody
- @collection.each do |transaction|
%tr.transaction
%td.transaction-date
= transaction.updated_at.strftime("%Y-%m-%d")
%td.description
= transaction.description
%td.payment-method
= t(transaction.payment_method.name.to_s)
%td.amount
= Spree::Money.new(transaction.amount)
%td.running_balance
= Spree::Money.new(transaction.balance)

View File

@@ -99,11 +99,14 @@
%td.balance.align-center{ 'ng-show' => 'columns.balance.visible'}
%span.state.white-space-nowrap{ 'ng-class' => 'customer.balance_status', 'ng-bind' => 'displayBalanceStatus(customer)' }
%span{ 'ng-bind' => '::customer.balance' }
%td.balance.align-center{ 'ng-show' => 'columns.credit.visible'}
%span{ 'ng-bind' => '::customer.available_credit' }
%td.balance.align-center{ 'ng-show' => 'columns.credit.visible', "data-turbo": true}
%a{ "ng-href": "{{customer.available_credit_url}}", "data-turbo-stream": "" }
%span{ 'ng-bind' => '::customer.available_credit' }
%td.actions
%a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" }
.text-center{ "ng-show": "filteredCustomers.length > customerLimit" }
%input{ type: 'button', value: t(:show_more), "ng-click": 'customerLimit = customerLimit + 20' }
%input{ type: 'button', value: t(:show_all_with_more, num: '{{ filteredCustomers.length - customerLimit }}'), "ng-click": 'customerLimit = filteredCustomers.length' }
#customer-account-transactions-modal-container

View File

@@ -894,6 +894,14 @@ en:
balance_due: "Balance Due"
destroy:
has_associated_subscriptions: "Delete failed: This customer has active subscriptions. Cancel them first."
customer_account_transaction:
index:
available_credit: "Available credit: %{available_credit}"
transaction_date: Transaction Date
description: Description
payment_method: Payment method
amount: Amount
running_balance: Running balance
column_preferences:
bulk_update:
success: "Column preferences saved"

View File

@@ -91,7 +91,9 @@ Openfoodnetwork::Application.routes.draw do
resources :inventory_items, only: [:create, :update]
resources :customers, only: [:index, :create, :update, :destroy, :show]
resources :customers, only: [:index, :create, :update, :destroy, :show] do
resources :customer_account_transaction, only: [:index]
end
resources :tag_rules, only: [] do
get :map_by_tag, on: :collection, format: :json

View File

@@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Admin::CustomerAccountTransactionController do
describe "GET /index" do
let(:enterprise_user) { create(:user, enterprises: [enterprise]) }
let(:enterprise) { create(:enterprise) }
let(:customer) { create(:customer, enterprise:) }
let!(:payment_method) {
create(
:payment_method,
name: CustomerAccountTransaction::DEFAULT_PAYMENT_METHOD_NAME,
distributors: [enterprise]
)
}
before do
login_as enterprise_user
end
it "returns a list of customer transactions" do
customer_account_transaction = create(:customer_account_transaction, customer:)
get admin_customer_customer_account_transaction_index_path(customer),
params: { format: :turbo_stream }
expect(response).to render_template("admin/customer_account_transaction/index")
end
context "with a non authorized customer" do
let(:customer) { create(:customer) }
it "returns unauthorized" do
customer_account_transaction = create(:customer_account_transaction, customer:)
get admin_customer_customer_account_transaction_index_path(customer),
params: { format: :turbo_stream }
expect(response).to redirect_to(unauthorized_path)
end
end
end
end