PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.1.1
Fluent Support – Helpdesk & Customer Support Ticket System v2.1.1
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
← All changes | app/Models/Ticket.php +3 -117 2.3.22.1.1 View file →
@@ -15,10 +15,8 @@
15 15 protected $table = 'fs_tickets';
16 16
17 17 protected $dates = ['waiting_since'];
18 18
19 - protected $appends = ['display_ticket_number'];
20 -
21 19 /**
22 20 * The attributes that are mass assignable.
23 21 *
24 22 * @var array
@@ -46,11 +44,9 @@
46 44 'first_response_time',
47 45 'total_close_time',
48 46 'resolved_at',
49 47 'closed_by',
50 - 'created_by',
51 - 'serial_number',
52 - 'ticket_number'
48 + 'created_by'
53 49 ];
54 50
55 51 public static function boot()
56 52 {
@@ -70,14 +66,8 @@
70 66 $model->waiting_since = current_time('mysql');
71 67
72 68 });
73 69
74 - static::created(function ($model) {
75 - if (empty($model->serial_number) || empty($model->ticket_number)) {
76 - $model->assignTicketNumber();
77 - }
78 - });
79 -
80 70 static::deleting(function ($model) {
81 71 //Delete the ticket meta
82 72 Meta::where('object_type', 'ticket_meta')->where('object_id', $model->id)->delete();
83 73 //Delete all cc info for the ticket
@@ -83,10 +73,8 @@
83 73 //Delete all cc info for the ticket
84 74 Meta::where('object_type', 'ticket')->where('object_id', $model->id)->delete();
85 75 //Delete draft info
86 76 Meta::where('object_type', '_fs_auto_draft')->where('object_id', $model->id)->delete();
87 - //Delete internal notifications and notification recipient rows for the ticket
88 - Notification::deleteByTicketId($model->id);
89 77 //delete the responses first (their attachments are cleaned up by Conversation::deleting)
90 78 Conversation::deleteAll($model->id);
91 79 // Delete ticket-level attachments (conversation_id IS NULL) and remove the ticket upload directory
92 80 $class = __NAMESPACE__ . '\Attachment';
@@ -103,11 +91,9 @@
103 91 protected $searchable = [
104 92 'content',
105 93 'title',
106 94 'slug',
107 - 'id',
108 - 'serial_number',
109 - 'ticket_number'
95 + 'id'
110 96 ];
111 97
112 98 /**
113 99 * Local scope to filter tickets by search/query string
@@ -219,41 +205,8 @@
219 205 return $query;
220 206 }
221 207
222 208 /**
223 - * Who replied last on this ticket, derived from the already-loaded
224 - * last_agent_response / last_customer_response timestamp columns.
225 - *
226 - * Returns 'agent', 'customer', or null. This is the per-ticket value behind
227 - * the `waiting_for_reply` filter and mirrors the timestamp comparison in
228 - * scopeWaitingOnly() (which lives in SQL, so it can't share this PHP code).
229 - *
230 - * Note: boot() seeds last_customer_response on creation, so a brand-new
231 - * ticket with no agent reply correctly resolves to 'customer' (awaiting an
232 - * agent). null is reserved for the rare case where neither timestamp is set.
233 - *
234 - * @return string|null
235 - */
236 - public function getLastReplyByAttribute()
237 - {
238 - $agentAt = $this->last_agent_response;
239 - $customerAt = $this->last_customer_response;
240 -
241 - if (!$agentAt && !$customerAt) {
242 - return null;
243 - }
244 - if (!$agentAt) {
245 - return 'customer';
246 - }
247 - if (!$customerAt) {
248 - return 'agent';
249 - }
250 -
251 - // Tie (same second) resolves to 'customer' — the waiting bias used by scopeWaitingOnly.
252 - return strtotime($customerAt) >= strtotime($agentAt) ? 'customer' : 'agent';
253 - }
254 -
255 - /**
256 209 * Local scope to filter tickets by not response by agent
257 210 * @param $query
258 211 * @return mixed
259 212 */
@@ -800,76 +753,8 @@
800 753 // Delete the ticket
801 754 $this->delete();
802 755 }
803 756
804 - public static function getNextSerialNumber()
805 - {
806 - $businessSettings = Helper::getOption('global_business_settings', []);
807 - $minNumber = (int) ($businessSettings['min_serial_number'] ?? 1);
808 - $minNumber = (int) apply_filters('fluent_support/min_serial_number', $minNumber);
809 -
810 - try {
811 - $lastTicketNumber = self::query()->max('serial_number');
812 - } catch (\Exception $e) {
813 - $lastTicketNumber = null;
814 - }
815 -
816 - $nextNumber = ((int) $lastTicketNumber) + 1;
817 -
818 - return max($nextNumber, $minNumber);
819 - }
820 -
821 - public static function isMinimumSerialNumberEnabled()
822 - {
823 - $businessSettings = Helper::getOption('global_business_settings', []);
824 - return ($businessSettings['enable_min_serial_number'] ?? 'no') === 'yes';
825 - }
826 -
827 - public static function getTicketPrefix($ticket = null)
828 - {
829 - $businessSettings = Helper::getOption('global_business_settings', []);
830 - $prefix = self::isMinimumSerialNumberEnabled() ? trim((string) ($businessSettings['ticket_prefix'] ?? '')) : '';
831 -
832 - $productId = $ticket ? $ticket->product_id : null;
833 -
834 - return apply_filters('fluent_support/ticket_prefix', $prefix, $ticket, $productId);
835 - }
836 -
837 - public function getDisplayTicketNumberAttribute()
838 - {
839 - return $this->ticket_number ?: ($this->serial_number ?: $this->id);
840 - }
841 -
842 - public function scopeWherePublicIdentifier($query, $identifier)
843 - {
844 - return $query->where('serial_number', $identifier);
845 - }
846 -
847 - protected function assignTicketNumber()
848 - {
849 - for ($attempt = 0; $attempt < 5; $attempt++) {
850 - $nextNumber = $this->serial_number ?: (self::isMinimumSerialNumberEnabled() ? self::getNextSerialNumber() : $this->id);
851 - $ticketNumber = $this->ticket_number ?: (self::getTicketPrefix($this) . $nextNumber);
852 -
853 - try {
854 - self::where('id', $this->id)->update([
855 - 'serial_number' => $nextNumber,
856 - 'ticket_number' => $ticketNumber
857 - ]);
858 - $this->serial_number = $nextNumber;
859 - $this->ticket_number = $ticketNumber;
860 -
861 - return $nextNumber;
862 - } catch (\Exception $e) {
863 - if (stripos($e->getMessage(), 'duplicate') === false) {
864 - throw $e;
865 - }
866 - }
867 - }
868 -
869 - throw new \RuntimeException('Could not allocate a unique ticket number.');
870 - }
871 -
872 757 public static function slugify($title)
873 758 {
874 759 $slug = sanitize_title($title, 'support-ticket-' . time(), 'display');
875 760 if (Ticket::where('slug', $slug)->first()) {
@@ -1216,4 +1101,5 @@
1216 1101
1217 1102 }
1218 1103
1219 1104 }
1105 +