mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
basic inteface to retrieve payment schedules
This commit is contained in:
parent
01a0612a4b
commit
def0778a4d
@ -23,7 +23,6 @@ class API::InvoicesController < API::ApiController
|
||||
p = params.require(:query).permit(:number, :customer, :date, :order_by, :page, :size)
|
||||
|
||||
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless p[:page].is_a? Integer
|
||||
|
||||
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless p[:size].is_a? Integer
|
||||
|
||||
order = InvoicesService.parse_order(p[:order_by])
|
||||
|
@ -5,6 +5,21 @@ class API::PaymentSchedulesController < API::ApiController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_payment_schedule, only: %i[download]
|
||||
|
||||
def list
|
||||
authorize PaymentSchedule
|
||||
|
||||
p = params.require(:query).permit(:reference, :customer, :date, :page, :size)
|
||||
|
||||
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless p[:page].is_a? Integer
|
||||
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless p[:size].is_a? Integer
|
||||
|
||||
@payment_schedules = PaymentScheduleService.list(
|
||||
p[:page],
|
||||
p[:size],
|
||||
reference: p[:reference], customer: p[:customer], date: p[:date]
|
||||
)
|
||||
end
|
||||
|
||||
def download
|
||||
authorize @payment_schedule
|
||||
send_file File.join(Rails.root, @payment_schedule.file), type: 'application/pdf', disposition: 'attachment'
|
||||
|
17
app/frontend/src/javascript/api/payment-schedule.ts
Normal file
17
app/frontend/src/javascript/api/payment-schedule.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import apiClient from './api-client';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { PaymentSchedule, PaymentScheduleIndexRequest } from '../models/payment-schedule';
|
||||
import wrapPromise, { IWrapPromise } from '../lib/wrap-promise';
|
||||
|
||||
export default class PaymentScheduleAPI {
|
||||
async list (query: PaymentScheduleIndexRequest): Promise<Array<PaymentSchedule>> {
|
||||
const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/list`, query);
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static list (query: PaymentScheduleIndexRequest): IWrapPromise<Array<PaymentSchedule>> {
|
||||
const api = new PaymentScheduleAPI();
|
||||
return wrapPromise(api.list(query));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { IApplication } from '../models/application';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Loader } from './loader';
|
||||
import { react2angular } from 'react2angular';
|
||||
import PaymentScheduleAPI from '../api/payment-schedule';
|
||||
|
||||
declare var Application: IApplication;
|
||||
|
||||
const paymentSchedulesList = PaymentScheduleAPI.list({ query: { page: 1, size: 20 } });
|
||||
|
||||
const PaymentSchedulesList: React.FC = () => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const paymentSchedules = paymentSchedulesList.read();
|
||||
|
||||
return (
|
||||
<div className="payment-schedules-list">
|
||||
<ul>
|
||||
{paymentSchedules.map(p => `<li>${p.reference}</li>`)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const PaymentSchedulesListWrapper: React.FC = () => {
|
||||
return (
|
||||
<Loader>
|
||||
<PaymentSchedulesList />
|
||||
</Loader>
|
||||
);
|
||||
}
|
||||
|
||||
Application.Components.component('paymentSchedulesList', react2angular(PaymentSchedulesListWrapper));
|
@ -1,7 +1,10 @@
|
||||
export interface PaymentScheduleItem {
|
||||
id: number,
|
||||
amount: number,
|
||||
due_date: Date
|
||||
due_date: Date,
|
||||
state: string,
|
||||
invoice_id: number,
|
||||
payment_method: string,
|
||||
details: {
|
||||
recurring: number,
|
||||
adjustment: number,
|
||||
@ -18,5 +21,25 @@ export interface PaymentSchedule {
|
||||
reference: string,
|
||||
payment_method: string,
|
||||
wallet_amount: number,
|
||||
items: Array<PaymentScheduleItem>
|
||||
items: Array<PaymentScheduleItem>,
|
||||
created_at: Date,
|
||||
chained_footprint: boolean,
|
||||
user: {
|
||||
name: string
|
||||
},
|
||||
operator: {
|
||||
id: number,
|
||||
first_name: string,
|
||||
last_name: string,
|
||||
}
|
||||
}
|
||||
|
||||
export interface PaymentScheduleIndexRequest {
|
||||
query: {
|
||||
reference?: string,
|
||||
customer?: string,
|
||||
date?: Date,
|
||||
page: number,
|
||||
size: number
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,10 @@
|
||||
<ng-include src="'/admin/invoices/list.html'"></ng-include>
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.invoices.payment_schedules_list' | translate }}" ng-show="$root.modules.invoicing" index="4">
|
||||
<payment-schedules-list />
|
||||
</uib-tab>
|
||||
|
||||
<uib-tab heading="{{ 'app.admin.invoices.invoicing_settings' | translate }}" index="1" class="invoices-settings">
|
||||
<ng-include src="'/admin/invoices/settings.html'"></ng-include>
|
||||
</uib-tab>
|
||||
|
12
app/policies/payment_schedule_policy.rb
Normal file
12
app/policies/payment_schedule_policy.rb
Normal file
@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Check the access policies for API::PaymentSchedulesController
|
||||
class PaymentSchedulePolicy < ApplicationPolicy
|
||||
def list?
|
||||
user.admin? || user.manager?
|
||||
end
|
||||
|
||||
def download?
|
||||
user.admin? || user.manager? || (record.invoicing_profile.user_id == user.id)
|
||||
end
|
||||
end
|
@ -98,7 +98,43 @@ class PaymentScheduleService
|
||||
|
||||
# save the results
|
||||
invoice.save
|
||||
payment_schedule_item.update_attributes(invoice_id: invoice.id, stp_invoice_id: stp_invoice.id)
|
||||
payment_schedule_item.update_attributes(invoice_id: invoice.id, stp_invoice_id: stp_invoice&.id)
|
||||
end
|
||||
|
||||
##
|
||||
# return a paginated list of PaymentSchedule, optionally filtered, with their associated PaymentScheduleItem
|
||||
# @param page {number} page number, used to paginate results
|
||||
# @param size {number} number of items per page
|
||||
# @param filters {Hash} allowed filters: reference, customer, date.
|
||||
##
|
||||
def self.list(page, size, filters = {})
|
||||
ps = PaymentSchedule.includes(:invoicing_profile, :payment_schedule_items, :subscription)
|
||||
.joins(:invoicing_profile)
|
||||
.page(page)
|
||||
.per(size)
|
||||
|
||||
|
||||
unless filters[:reference].nil?
|
||||
ps = ps.where(
|
||||
'payment_schedules.reference LIKE :search',
|
||||
search: "#{filters[:reference]}%"
|
||||
)
|
||||
end
|
||||
unless filters[:customer].nil?
|
||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||
ps = ps.where(
|
||||
'invoicing_profiles.first_name ILIKE :search OR invoicing_profiles.last_name ILIKE :search',
|
||||
search: "%#{filters[:customer]}%"
|
||||
)
|
||||
end
|
||||
unless filters[:date].nil?
|
||||
ps = ps.where(
|
||||
"date_trunc('day', payment_schedules.created_at) = :search",
|
||||
search: "%#{DateTime.iso8601(filters[:date]).to_time.to_date}%"
|
||||
)
|
||||
end
|
||||
|
||||
ps
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -7,7 +7,7 @@ json.array!(@invoices) do |invoice|
|
||||
json.extract! invoice, :id, :created_at, :reference, :invoiced_type, :avoir_date
|
||||
json.user_id invoice.invoicing_profile.user_id
|
||||
json.total invoice.total / 100.00
|
||||
|
||||
|
||||
json.name invoice.invoicing_profile.full_name
|
||||
json.has_avoir invoice.refunded?
|
||||
json.is_avoir invoice.is_a?(Avoir)
|
||||
|
20
app/views/api/payment_schedules/list.json.jbuilder
Normal file
20
app/views/api/payment_schedules/list.json.jbuilder
Normal file
@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.array! @payment_schedules do |ps|
|
||||
json.extract! ps, :id, :reference, :created_at, :payment_method
|
||||
json.total ps.total / 100.00
|
||||
json.chained_footprint ps.check_footprint
|
||||
json.user do
|
||||
json.name ps.invoicing_profile.full_name
|
||||
end
|
||||
if ps.operator_profile
|
||||
json.operator do
|
||||
json.id ps.operator_profile.user_id
|
||||
json.extract! ps.operator_profile, :first_name, :last_name
|
||||
end
|
||||
end
|
||||
json.items ps.payment_schedule_items do |item|
|
||||
json.extract! item, :id, :due_date, :state, :invoice_id, :payment_method
|
||||
json.amount item.amount / 100.00
|
||||
end
|
||||
end
|
@ -16,7 +16,7 @@ class PaymentScheduleItemWorker
|
||||
if stp_invoice.status == 'paid'
|
||||
##### Stripe / Successfully paid
|
||||
PaymentScheduleService.new.generate_invoice(psi, stp_invoice)
|
||||
psi.update_attributes(state: 'paid')
|
||||
psi.update_attributes(state: 'paid', payment_method: 'stripe')
|
||||
else
|
||||
##### Stripe / Payment error
|
||||
NotificationCenter.call type: 'notify_admin_payment_schedule_failed',
|
||||
|
@ -414,6 +414,7 @@ en:
|
||||
credit_note: "Credit note"
|
||||
display_more_invoices: "Display more invoices..."
|
||||
no_invoices_for_now: "No invoices for now."
|
||||
payment_schedules_list: "Payment schedules"
|
||||
invoicing_settings: "Invoicing settings"
|
||||
warning_invoices_disabled: "Warning : invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
|
||||
change_logo: "Change logo"
|
||||
|
@ -414,6 +414,7 @@ fr:
|
||||
credit_note: "Avoir"
|
||||
display_more_invoices: "Afficher plus de factures..."
|
||||
no_invoices_for_now: "Aucune facture pour le moment."
|
||||
payment_schedules_list: "Échéanciers de paiement"
|
||||
invoicing_settings: "Paramètres de facturation"
|
||||
warning_invoices_disabled: "Attention : les factures ne sont pas activées. Aucune facture ne sera générée par Fab-manager. Vous devez néanmoins remplir correctement les informations ci-dessous, particulièrement la TVA."
|
||||
change_logo: "Changer le logo"
|
||||
|
@ -111,7 +111,8 @@ Rails.application.routes.draw do
|
||||
get 'first', action: 'first', on: :collection
|
||||
end
|
||||
|
||||
resources :payment_schedules, only: %i[index show] do
|
||||
resources :payment_schedules, only: %i[show] do
|
||||
post 'list', action: 'list', on: :collection
|
||||
get 'download', on: :member
|
||||
end
|
||||
|
||||
|
@ -9,6 +9,7 @@ class CreatePaymentScheduleItems < ActiveRecord::Migration[5.2]
|
||||
t.string :state, default: 'new'
|
||||
t.jsonb :details, default: '{}'
|
||||
t.string :stp_invoice_id
|
||||
t.string :payment_method
|
||||
t.belongs_to :payment_schedule, foreign_key: true
|
||||
t.belongs_to :invoice, foreign_key: true
|
||||
t.string :footprint
|
||||
|
@ -1473,6 +1473,7 @@ CREATE TABLE public.payment_schedule_items (
|
||||
state character varying DEFAULT 'new'::character varying,
|
||||
details jsonb DEFAULT '"{}"'::jsonb,
|
||||
stp_invoice_id character varying,
|
||||
payment_method character varying,
|
||||
payment_schedule_id bigint,
|
||||
invoice_id bigint,
|
||||
footprint character varying,
|
||||
|
Loading…
x
Reference in New Issue
Block a user