Групповое выставление счетов / генерация PDF с индикацией прогресса PHP и AJAX - PullRequest
1 голос
/ 15 июня 2011

ОК, так что я подхожу к стадии текущего проекта, где я буду внедрять выставление счетов, и подумав об этом, я подумал, что увижу, как вы, ребята, подойдете к этой проблеме. Если это уместно, я использую CodeIgniter, jQuery, jQuery UI и имею полный контроль над сервером, использую PHP 5.3 и Apache 2.2.16. Рабочий сервер работает под управлением Debian Squeeze.

Так что мой запрос таков.

  • Приложение, которое я разрабатываю, будет обрабатывать счета
  • Счета могут быть созданы по одному или в серии (из диапазона дат)
  • Все счета должны иметь PDF-файл, созданный и сохраненный на сервере. Я использую mPDF.
  • Некоторые счета могут быть отправлены клиентам по электронной почте, другие должны быть в формате PDF и, если возможно, отправлены на принтер (lpr -p?), Прямо из PHP, если это возможно
  • Счета-фактуры проводятся, как правило, раз в две недели
  • Выполнение счетов-фактур обычно может включать создание более 100 счетов-фактур
  • Некоторые счета могут быть достаточно большими, хотя типичный размер PDF может быть 2-5 страниц на счет

В основном я хотел бы получить несколько советов. Основные области, по которым я ищу советы:

  • Пакетное выставление счетов - если это было сделано с помощью одного запроса браузера, это может занять несколько минут, а PHP может превысить максимальное время выполнения. Я подумал, что, возможно, это можно сделать через AJAX, где jQuery извлекает список счетов-фактур, а затем перебирает список, запрашивая у PHP создание PDF-файла и обработку счета. Таким образом, вместо одного большого запроса, у вас есть много меньших? Это рекомендуется? Есть ли лучший подход?
  • Пакетная печать. Пользователи беспокоятся о необходимости вручную печатать десятки счетов-фактур при каждом запуске, и это понятно. Как лучше всего распечатать пакетные счета из PHP на локальном принтере? Я читал об отправке вывода на принтер, используя lpr на коробке, но я беспокоюсь, что во время пакетной процедуры, скажем, 100 PDF, пара может в конечном итоге потеряться. Есть ли лучший способ?
  • Отчет о проделанной работе. Типичное вращающееся колесо может стать утомительным, и я знаю, что пользователи запрашивали более подробные обновления прогресса. Любой совет по этому поводу? Я знаю, что с помощью описанного выше метода многих небольших запросов вы можете легко получить отчет AJAX: Создание PDF для Cust 1 ... ВЫПОЛНЕНО ... Отправка PDF-документов в Cust 1 ... ВЫПОЛНЕНО ... Создание PDF для клиента 2 ... и так далее.
  • База данных ACIDity и обработка ошибок. Выставление счетов является сложным и, очевидно, чувствительным с учетом суммы денег ... любые советы, касающиеся логики приложения для транзакций, обработки ошибок генерации PDF / ошибок электронной почты для отката счетов и т. Д., Были бы хорошими.

Я оставлю это открытым для совета. Будем благодарны за любые советы, предложения или комментарии, которые вы можете пожелать.

Большое спасибо.

Ответы [ 2 ]

1 голос
/ 15 июня 2011

Я бы никогда не рекомендовал запускать такую ​​работу из браузера.Это то, что лучше всего запускать как консольный скрипт.Теперь вы можете при необходимости удалить консольный скрипт из браузера.

В качестве консольного задания вам не нужно беспокоиться о прерывании процесса браузером или соединении браузера с сервером.

Я бы, вероятно, сначала выполнил бы всю обработку данных для счетов-фактур и убедился бы, что процесс является атомарным.Затем я должен был создать PDF-файлы потом.Технически, вы должны иметь возможность восстановить PDF-файл из данных счета в любое время.

0 голосов
/ 05 августа 2011

Просто выполнил это сейчас и подумал, что опубликую решение, которое я использовал, чтобы другие могли его увидеть.

  1. В соответствии с рекомендацией от datasage я сконцентрировался на написании надежной процедуры, чтобы сначала выполнить обработку базы данных (с использованием транзакций MySQL).

  2. Затем я написал функциональность для обработки отдельных счетов (например, создание одного PDF с mPDF, отправка одного PDF по электронной почте) по таким URL-адресам, как /invoicing/pdf/123 и /invoicing/send/123

  3. Для пакетной клиентской процедуры сначала я написал серверный прослушиватель, который возвращал бы объект JSON с номерами счетов, которые необходимо отправить, с соответствующим именем клиента и URI для отправки:

     {"invoice_number":1,"customer":"Acme Inc.","uri":"/invoicing/send/1"},
     {"invoice_number":2,"customer":"Another Company","uri":"/invoicing/send/2"},
     {"invoice_number":3,"customer":"Yet Another.","uri":"/invoicing/send/3"},
    
  4. Вы можете видеть, куда я иду с этим. Наконец, я написал Javascript на стороне клиента для цикла JSON и выполнения запросов. Однако проблема, с которой я столкнулся, заключалась в использовании $.ajax или любого другого собственного вызова jQuery, все запросы запускались бы одновременно, а Chrome ограничивал количество подключений к серверу шестью, поэтому отправлялись только шесть счетов. Кроме того, переключение $.ajax на использование async:false приводило к зависанию браузера до тех пор, пока все запросы не были выполнены успешно. Поэтому я наткнулся на этот плагин: http://plugins.jquery.com/project/ajaxq, который "поставил бы в очередь" вызовы AJAX и обеспечил нужный мне эффект.

  5. Наконец, код на стороне клиента у меня выглядит примерно так:

        $(batch).each(function(key,value){
    
            // TODO: make this better
            // For now, uses a plugin which enables us to carry out sequential/synchronous AJAX calls to the server
            $.ajaxq("batch_email", {
                url: value.uri,
                format: 'json',
                success: function(response) { 
                    completed++;
                    $('#progress').val(completed);
    
                    if (response.result == "error") {
                        $('#batch_status').append('<p class="notification error">Failed: '+value.customer_name+'</p>');
                    }
    
                    if (completed != num) {
                        $('#text').html('<img src="'+base_url+'static/img/spinner.gif" style="vertical-align:middle;margin-right:10px;" />'+batch[key+1].customer_name+'...');
                    } else {
                        $('#text').html('Finished');
                        $('#progress').after('<div class="tc"><a href="'+base_url+'customer_invoicing" class="blue button">Return to invoicing</a></a>');
                    }
                }
            });
    
        });
    

Еще нужно немного привести в порядок перед развертыванием, но это, безусловно, работает. Как вы можете видеть, я использовал индикатор прогресса HTML5, чтобы показать ход выполнения процедуры.

Надеюсь, это поможет любому, кто может наткнуться на этот пост в ближайшие недели / месяцы!

С наилучшими пожеланиями

...