1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-26 20:54:21 +01:00

[feature] partial load of invoices list

This commit is contained in:
Sylvain 2016-05-31 10:02:27 +02:00
parent 820d8bba53
commit 3593f293ce
11 changed files with 171 additions and 8 deletions

View File

@ -3,15 +3,34 @@
## ##
# Controller used in the admin invoices listing page # Controller used in the admin invoices listing page
## ##
Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'Invoice', '$uibModal', "growl", "$filter", 'Setting', 'settings', '_t' Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'Invoice', 'invoices', '$uibModal', "growl", "$filter", 'Setting', 'settings', '_t'
, ($scope, $state, Invoice, $uibModal, growl, $filter, Setting, settings, _t) -> , ($scope, $state, Invoice, invoices, $uibModal, growl, $filter, Setting, settings, _t) ->
### PRIVATE STATIC CONSTANTS ###
# 10 invoices loaded each time we click on 'load more...'
INVOICES_PER_PAGE = 10
### PUBLIC SCOPE ### ### PUBLIC SCOPE ###
## List of all users invoices ## List of all users invoices
$scope.invoices = Invoice.query() $scope.invoices = invoices
# Invoices filters
$scope.searchInvoice =
date: null
name: ''
reference: ''
# currently displayed page of invoices (search results)
$scope.page = 1
# true when all invoices are loaded
$scope.noMoreResults = false
## Default invoices ordering/sorting ## Default invoices ordering/sorting
$scope.orderInvoice = '-reference' $scope.orderInvoice = '-reference'
@ -61,6 +80,9 @@ Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'I
else else
$scope.orderInvoice = orderBy $scope.orderInvoice = orderBy
resetSearchInvoice()
invoiceSearch()
## ##
@ -323,6 +345,26 @@ Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'I
##
# Callback when any of the filters changes.
# Full reload the results list
##
$scope.handleFilterChange = ->
resetSearchInvoice()
invoiceSearch()
##
# Callback for the 'load more' button.
# Will load the next results of the current search, if any
##
$scope.showNextInvoices = ->
$scope.page += 1
invoiceSearch(true)
### PRIVATE SCOPE ### ### PRIVATE SCOPE ###
## ##
@ -381,6 +423,40 @@ Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'I
##
# Reinitialize the context of invoices' search to display new results set
##
resetSearchInvoice = ->
$scope.page = 1
$scope.noMoreResults = false
##
# Run a search query with the current parameters set concerning invoices, then affect or concat the results
# to $scope.invoices
# @param concat {boolean} if true, the result will be append to $scope.invoices instead of being affected
##
invoiceSearch = (concat) ->
Invoice.list {
query:
number: $scope.searchInvoice.reference
customer: $scope.searchInvoice.name
date: $scope.searchInvoice.date
order_by: $scope.orderInvoice
page: $scope.page
size: INVOICES_PER_PAGE
}, (invoices) ->
if (invoices.length < INVOICES_PER_PAGE)
$scope.noMoreResults = true
if concat
$scope.invoices = $scope.invoices.concat(invoices)
else
$scope.invoices = invoices
## !!! MUST BE CALLED AT THE END of the controller ## !!! MUST BE CALLED AT THE END of the controller
initialize() initialize()
] ]

View File

@ -127,7 +127,7 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
searchText: '' searchText: ''
## Members ordering/sorting. Default: not sorted ## Members ordering/sorting. Default: not sorted
order: 'id' order: 'id'
## current displayed page of members ## currently displayed page of members
page: 1 page: 1
## true when all members where loaded ## true when all members where loaded
noMore: false noMore: false
@ -186,15 +186,26 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
growl.error(_t('unable_to_delete_the_administrator')) growl.error(_t('unable_to_delete_the_administrator'))
##
# Callback for the 'load more' button.
# Will load the next results of the current search, if any
##
$scope.showNextMembers = -> $scope.showNextMembers = ->
$scope.member.page += 1 $scope.member.page += 1
memberSearch(true) memberSearch(true)
##
# Callback when the search field content changes: reload the search results
##
$scope.updateTextSearch = -> $scope.updateTextSearch = ->
resetSearchMember() resetSearchMember()
memberSearch() memberSearch()
### PRIVATE SCOPE ### ### PRIVATE SCOPE ###
## ##

View File

@ -669,6 +669,11 @@ angular.module('application.router', ['ui.router']).
'invoice_logo' 'invoice_logo'
]").$promise ]").$promise
] ]
invoices: [ 'Invoice', (Invoice) ->
Invoice.list({
query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 10 }
}).$promise
]
translations: [ 'Translations', (Translations) -> translations: [ 'Translations', (Translations) ->
Translations.query('app.admin.invoices').$promise Translations.query('app.admin.invoices').$promise
] ]

View File

@ -5,4 +5,8 @@ Application.Services.factory 'Invoice', ["$resource", ($resource)->
{id: "@id"}, {id: "@id"},
update: update:
method: 'PUT' method: 'PUT'
list:
url: '/api/invoices/list'
method: 'POST'
isArray: true
] ]

View File

@ -26,7 +26,7 @@
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon" translate>{{ 'invoice_#_' }}</span> <span class="input-group-addon" translate>{{ 'invoice_#_' }}</span>
<input type="text" ng-model="searchInvoice.reference" class="form-control" placeholder=""> <input type="text" ng-model="searchInvoice.reference" class="form-control" placeholder="" ng-change="handleFilterChange()">
</div> </div>
</div> </div>
</div> </div>
@ -35,7 +35,7 @@
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon" translate>{{ 'customer_' }}</span> <span class="input-group-addon" translate>{{ 'customer_' }}</span>
<input type="text" ng-model="searchInvoice.name" class="form-control" placeholder=""> <input type="text" ng-model="searchInvoice.name" class="form-control" placeholder="" ng-change="handleFilterChange()">
</div> </div>
</div> </div>
</div> </div>
@ -44,7 +44,7 @@
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<span class="input-group-addon">{{ "date_" | translate }}</span> <span class="input-group-addon">{{ "date_" | translate }}</span>
<input type="date" ng-model="searchInvoice.date" class="form-control"> <input type="date" ng-model="searchInvoice.date" class="form-control" ng-change="handleFilterChange()">
</div> </div>
</div> </div>
</div> </div>
@ -69,7 +69,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="invoice in invoices | filter:searchInvoice | orderBy:orderInvoice"> <tr ng-repeat="invoice in invoices">
<td>{{ invoice.reference }}</td> <td>{{ invoice.reference }}</td>
<td ng-if="!invoice.is_avoir">{{ invoice.date | amDateFormat:'L LTS' }}</td> <td ng-if="!invoice.is_avoir">{{ invoice.date | amDateFormat:'L LTS' }}</td>
<td ng-if="invoice.is_avoir">{{ invoice.date | amDateFormat:'L' }}</td> <td ng-if="invoice.is_avoir">{{ invoice.date | amDateFormat:'L' }}</td>
@ -91,6 +91,9 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="text-center">
<button class="btn btn-warning" ng-click="showNextInvoices()" ng-hide="noMoreResults"><i class="fa fa-search-plus" aria-hidden="true"></i> {{ 'display_more_invoices' | translate }}</button>
</div>
<p ng-if="invoices.length == 0" translate>{{ 'no_invoices_for_now' }}</p> <p ng-if="invoices.length == 0" translate>{{ 'no_invoices_for_now' }}</p>
</div> </div>

View File

@ -12,6 +12,51 @@ class API::InvoicesController < API::ApiController
send_file File.join(Rails.root, @invoice.file), :type => 'application/pdf', :disposition => 'attachment' send_file File.join(Rails.root, @invoice.file), :type => 'application/pdf', :disposition => 'attachment'
end end
def list
authorize Invoice
p = params.require(:query).permit(:number, :customer, :date, :order_by, :page, :size)
unless p[:page].is_a? Integer
render json: {error: 'page must be an integer'}, status: :unprocessable_entity
end
unless p[:size].is_a? Integer
render json: {error: 'size must be an integer'}, status: :unprocessable_entity
end
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
case order_key
when 'reference'
order_key = 'invoices.reference'
when 'date'
order_key = 'invoices.created_at'
when 'total'
order_key = 'invoices.total'
when 'name'
order_key = 'profiles.first_name'
else
order_key = 'invoices.id'
end
@invoices = Invoice.includes(:avoir, :invoiced, invoice_items: [:subscription, :invoice_item], user: [:profile, :trainings])
.joins(:user => :profile)
.order("#{order_key} #{direction}")
.page(p[:page])
.per(p[:size])
# ILIKE => PostgreSQL case-insensitive LIKE
@invoices = @invoices.where('invoices.reference LIKE :search', search: "#{p[:number].to_s}%") if p[:number].size > 0
@invoices = @invoices.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search', search: "%#{p[:customer]}%") if p[:customer].size > 0
@invoices = @invoices.where("date_trunc('day', invoices.created_at) = :search", search: "%#{DateTime.iso8601(p[:date]).to_time.to_date.to_s}%") unless p[:date].nil?
@invoices
end
# only for create avoir # only for create avoir
def create def create
authorize Invoice authorize Invoice

View File

@ -10,4 +10,8 @@ class InvoicePolicy < ApplicationPolicy
def create? def create?
user.is_admin? user.is_admin?
end end
def list?
user.is_admin?
end
end end

View File

@ -0,0 +1,12 @@
json.array!(@invoices) do |invoice|
json.extract! invoice, :id, :created_at, :reference, :invoiced_type, :user_id, :avoir_date
json.total (invoice.total / 100.00)
json.url invoice_url(invoice, format: :json)
json.name invoice.user.profile.full_name
json.has_avoir invoice.has_avoir
json.is_avoir invoice.is_a?(Avoir)
json.is_subscription_invoice invoice.is_subscription_invoice?
json.stripe invoice.stp_invoice_id?
json.date invoice.is_a?(Avoir) ? invoice.avoir_date : invoice.created_at
json.prevent_refund invoice.prevent_refund?
end

View File

@ -160,6 +160,7 @@ en:
invoice_#: "Invoice #" invoice_#: "Invoice #"
customer: "Customer" customer: "Customer"
credit_note: "Credit note" credit_note: "Credit note"
display_more_invoices: "Display more invoices..."
invoicing_settings: "Invoicing settings" invoicing_settings: "Invoicing settings"
change_logo: "Change logo" change_logo: "Change logo"
john_smith: "John Smith" john_smith: "John Smith"

View File

@ -160,6 +160,7 @@ fr:
invoice_#: "Facture n°" invoice_#: "Facture n°"
customer: "Client" customer: "Client"
credit_note: "Avoir" credit_note: "Avoir"
display_more_invoices: "Afficher plus de factures ..."
invoicing_settings: "Paramètres de facturation" invoicing_settings: "Paramètres de facturation"
change_logo: "Changer le logo" change_logo: "Changer le logo"
john_smith: "Jean Dupont" john_smith: "Jean Dupont"

View File

@ -79,6 +79,7 @@ Rails.application.routes.draw do
resources :invoices, only: [:index, :show, :create] do resources :invoices, only: [:index, :show, :create] do
get ':id/download', action: 'download', on: :collection get ':id/download', action: 'download', on: :collection
post 'list', action: 'list', on: :collection
end end
# for admin # for admin