3 if (isset($_POST['show_reports'])) {
4 header(sprintf("Location: http%s://%s/%s/from/%s/to/%s", ($_SERVER['HTTPS']) ? "s" : "", $_SERVER['HTTP_HOST'], $module, $_POST['from'], $_POST['to']));
8 function show_reports_form($from = null, $to = null) {
9 form("noprint standout");
10 echo "<p>Show reports covering the period from ";
12 /* Default to last month. */
13 list($y, $m, $d) = explode('-', date('Y-m-d', time()));
15 $now = mktime(0, 0, 0, $m, $d, $y);
16 $first = mktime(0, 0, 0, $m, 1, $y);
17 $last = $first - 86400;
18 $date = date('Y-m-d', $last);
19 if (is_null($to)) $to = $date;
20 list($y, $m, $d) = explode('-', $date);
21 $first = mktime(0, 0, 0, $m, 1, $y);
22 if (is_null($from)) $from = date('Y-m-d', $first);
24 for ($i = 0; $i < 2; $i++) {
26 list ($y, $m, $d) = explode('-', date('Y-m-d', $date));
27 $date = mktime(0, 0, 0, $m, 1, $y);
29 $oldest = date('Y-m-d', $date);
32 datepicker("from", $from, true, null, false, "to");
34 datepicker("to", $to, true, "from", false);
36 submit("show_reports", "Show");
40 function check_report_dates($from, $to) {
41 list($y, $m, $d) = explode('-', $from);
42 if (! checkdate($m, $d, $y)) {
43 echo "<p>Invalid report start date!</p>\n";
46 $start = mktime(0, 0, 0, $m, $d, $y);
48 list($y, $m, $d) = explode('-', $to);
49 if (! checkdate($m, $d, $y)) {
50 echo "<p>Invalid report end date!</p>\n";
53 $end = mktime(0, 0, 0, $m, $d, $y);
56 echo "<p>Report end date is earlier than start date!</p>\n";
63 function show_order_report($from, &$order_state_ids) {
64 echo "<h3>Orders by week</h3>\n";
66 /* Handle missing weeks at the start of the range. */
67 $dbh = Propel::getConnection();
68 $sth = $dbh->prepare("select yearweek(:from)");
69 $sth->execute(array(':from' => $from));
70 list($first_week) = $sth->fetch();
71 $year_offset = substr($first_week, 0, 4);
72 $week_offset = substr($first_week, 4, 2) - 1;
74 $q = new OrderStateQuery;
75 $q->filterById($order_state_ids);
76 $q->withColumn('yearweek(updated)', 'week');
77 $q->withColumn('count(*)', 'count');
78 $q->addGroupByColumn('week')->orderByUpdated();
83 echo "<table class=\"report\">\n";
84 foreach ($rows as $row) {
86 Convert week of year to date range.
87 Beware that week 201401 comes after 201352.
89 $yearweek = $row->getWeek();
90 $y = substr($yearweek, 0, 4);
91 $w = substr($yearweek, 4, 2);
92 $week = (($y - $year_offset) * 52) + ($w - $week_offset);
93 $total += $row->getCount();
94 /* Fill in missing weeks. XXX */
95 for ($missing_week = $last_week + 1; $missing_week < $week; $missing_week++) {
97 printf(" <td align=\"right\">0</td><td>Week %d</td>\n", $missing_week);
101 printf(" <td align=\"right\">%d</td><td>Week %d</td>\n", $row->getCount(), $week);
106 echo " <td align=\"right\" class=\"strong\">$total</td><td class=\"strong\">Total</td>\n";
111 function show_postcode_report(&$order_ids) {
112 echo "<h3>Orders by postcode</h3>\n";
115 No regex replace support in MySQL so we'll have to retrieve all records
116 and group the postcodes ourselves.
119 $q->filterById($order_ids);
120 $q->join("Beneficiary");
121 /* No foreign key so we need to list the two tables. */
122 $q->join("Beneficiary.Address");
123 /* Not a FoodOrder column so we need to ask for it explicitly. */
124 $q->withColumn('upper(postcode)', 'postcode');
128 $postcodes = array();
129 foreach ($rows as $row) {
130 $postcode = preg_replace('/\s*[0-9][A-Z]+$/', '', trim($row->getPostcode()));
131 if (! $postcode) $postcode = "Unknown";
132 $postcodes[$postcode]++;
137 echo "<table class=\"report\">\n";
138 foreach ($postcodes as $postcode => $count) {
140 printf(" <td align=\"right\">%d</td><td>%s</td>\n", $count, htmlspecialchars($postcode));
144 echo " <td align=\"right\" class=\"strong\">$total</td><td class=\"strong\">Total</td>\n";
149 function show_contents_report(&$order_ids, $parcel_size, $grand_total) {
150 global $parcel_sizes, $parcel_contents;
153 for ($i = count($parcel_sizes); $i < count($parcel_contents); $i++) {
155 $q->filterById($order_ids);
156 $q->where(sprintf("parcel & %d", $parcel_size));
157 $q->where(sprintf("parcel & %d", (1 << $i)));
158 $contents = $q->find();
159 $total += count($contents);
160 echo "<tr class=\"small\">\n";
161 printf(" <td align=\"right\">%d</td><td>%s</td>\n", count($contents), htmlspecialchars($parcel_contents[$i]));
165 /* No special contents. */
166 echo "<tr class=\"small\">\n";
167 printf(" <td align=\"right\">%d</td><td>%s no special contents</td>\n", $grand_total - $total, htmlspecialchars($parcel_sizes[$parcel_size >> 1]));
171 function show_parcel_report(&$order_ids) {
172 global $parcel_sizes;
173 echo "<h3>Orders by parcel type</h3>\n";
176 $q->filterById($order_ids);
177 $q->withColumn(sprintf("parcel & %d", (1 << count($parcel_sizes)) - 1), 'size');
178 $q->withColumn('count(*)', 'count');
179 $q->addGroupByColumn('size')->addAscendingOrderByColumn('size');
182 echo "<table class=\"report\">\n";
183 foreach ($rows as $row) {
185 $requester = get_contact_by_id($row->getRequesterId());
186 printf(" <td align=\"right\">%d</td><td>%s</td>\n", $row->getCount(), htmlspecialchars($parcel_sizes[$row->getSize() >> 1]));
187 $total += $row->getCount();
189 show_contents_report($order_ids, $row->getSize(), $row->getCount());
192 echo " <td align=\"right\" class=\"strong\">$total</td><td class=\"strong\">Total</td>\n";
197 function show_requester_report(&$order_ids) {
198 echo "<h3>Orders by referrer</h3>\n";
201 $q->filterById($order_ids);
202 $q->withColumn('count(*)', 'count');
203 $q->groupByRequesterId()->addDescendingOrderByColumn('count');
206 echo "<table class=\"report\">\n";
208 foreach ($rows as $row) {
210 $requester = get_contact_by_id($row->getRequesterId());
211 printf(" <td align=\"right\">%d</td><td>%s</td>\n", $row->getCount(), htmlspecialchars($requester->getDisplayname()));
212 $total += $row->getCount();
216 echo " <td align=\"right\" class=\"strong\">$total</td><td class=\"strong\">Total</td>\n";
221 function show_reports($from, $to) {
222 if (! check_report_dates($from, $to)) return;
224 echo "<p>Showing reports for the period <strong>$from</strong> to <strong>$to</strong>.</p>\n";
227 $order_ids = array();
228 $order_state_ids = array();
229 /* XXX: Order 51 changed to state delivered in May then updated in June. */
230 $dbh = Propel::getConnection();
231 $sth = $dbh->prepare("select * from OrderState o where updated=(select min(updated) from OrderState where order_id=o.order_id and state & " . $GLOBALS['STATE_DELIVERED'] . ") and updated between '$from' and '$to'");
233 $order_states = OrderStatePeer::populateObjects($sth);
235 foreach ($order_states as $order_state) {
236 $order_id = $order_state->getOrderId();
237 $order_ids[] = $order_id;
238 if (! $dups[$order_id]) $order_state_ids[] = $order_state->getId();
239 $dups[$order_id] = true;
242 $q->filterById($order_ids);
244 if (! count($order_ids)) {
245 echo "<p>No results!</p>\n";
249 show_order_report($from, $order_state_ids);
250 show_postcode_report($order_ids);
251 show_parcel_report($order_ids);
252 show_requester_report($order_ids);
255 if (count($parameters)) {
256 if ($parameters[0] == "from") {
257 $from = $parameters[1];
258 if ($parameters[2] == "to") $to = $parameters[3];
259 show_reports($from, $to);
262 show_reports_form($from, $to);