<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/7460">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_queue: Add feature to set wrapuptime on the queue member<br><br>This patch adds the ability to set the wrapuptime on the queue member<br>config.<br><br>When the option is set the wrapuptime on the queue member is used instead<br>of the queue's wrapuptime.<br><br>ASTERISK-27483 #close<br><br>Change-Id: I11c85809537f974eb44dc5bbf82bcedd8a458902<br>---<br>M CHANGES<br>M apps/app_queue.c<br>M configs/samples/queues.conf.sample<br>A contrib/ast-db-manage/config/versions/e2f04d309071_add_wrapuptime_to_queue_members.py<br>4 files changed, 88 insertions(+), 8 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/CHANGES b/CHANGES<br>index bd1ca67..bd11c6c 100644<br>--- a/CHANGES<br>+++ b/CHANGES<br>@@ -37,6 +37,12 @@<br>  * The ContactInfo event's contact_status field is now set to "NonQualified"<br>    when a contact exists but has not been qualified.<br> <br>+app_queue<br>+------------------<br>+ * Added the ability to set the wrapuptime in the configuration of member.<br>+   When set the wrapuptime on the member is used instead of the wrapuptime<br>+   defined for the queue itself.<br>+<br> ------------------------------------------------------------------------------<br> --- Functionality changes from Asterisk 15.1.0 to Asterisk 15.2.0 ------------<br> ------------------------------------------------------------------------------<br>diff --git a/apps/app_queue.c b/apps/app_queue.c<br>index a140847..af8b3b8 100644<br>--- a/apps/app_queue.c<br>+++ b/apps/app_queue.c<br>@@ -1,7 +1,7 @@<br> /*<br>  * Asterisk -- An open source telephony toolkit.<br>  *<br>- * Copyright (C) 1999 - 2016, Digium, Inc.<br>+ * Copyright (C) 1999 - 2017, Digium, Inc.<br>  *<br>  * Mark Spencer <markster@digium.com><br>  *<br>@@ -1586,6 +1586,7 @@<br>  char reason_paused[80];              /*!< Reason of paused if member is paused */<br>  int queuepos;                        /*!< In what order (pertains to certain strategies) should this member be called? */<br>  int callcompletedinsl;               /*!< Whether the current call was completed within service level */<br>+  int wrapuptime;                      /*!< Wrapup Time */<br>   time_t starttime;                    /*!< The time at which the member answered the current caller. */<br>     time_t lastcall;                     /*!< When last successful call was hungup */<br>  time_t lastpause;                    /*!< When started the last pause */<br>@@ -1824,6 +1825,21 @@<br> {<br>       struct call_queue *q = obj, *q2 = arg;<br>        return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;<br>+}<br>+<br>+/*!<br>+ * \brief Return wrapuptime<br>+ *<br>+ * This function checks if wrapuptime in member is set and return this value.<br>+ * Otherwise return value the wrapuptime in the queue configuration<br>+ * \return integer value<br>+ */<br>+static int get_wrapuptime(struct call_queue *q, struct member *member)<br>+{<br>+  if (member->wrapuptime) {<br>+         return member->wrapuptime;<br>+        }<br>+    return q->wrapuptime;<br> }<br> <br> /*! \internal<br>@@ -2309,8 +2325,12 @@<br>                       if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {<br>                             ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);<br>                               break;<br>-                       } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {<br>-                           ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);<br>+                        } else if ((conditions & QUEUE_EMPTY_WRAPUP)<br>+                             && member->lastcall<br>+                               && get_wrapuptime(q, member)<br>+                         && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {<br>+                              ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",<br>+                                    member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));<br>                          break;<br>                        } else {<br>                              ao2_ref(member, -1);<br>@@ -2436,6 +2456,7 @@<br> static int is_member_available(struct call_queue *q, struct member *mem)<br> {<br>    int available = 0;<br>+   int wrapuptime;<br> <br>    switch (mem->status) {<br>             case AST_DEVICE_INVALID:<br>@@ -2459,7 +2480,8 @@<br>       }<br> <br>  /* Let wrapuptimes override device state availability */<br>-     if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {<br>+ wrapuptime = get_wrapuptime(q, mem);<br>+ if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {<br>              available = 0;<br>        }<br>     return available;<br>@@ -3354,6 +3376,7 @@<br>      int penalty = 0;<br>      int paused  = 0;<br>      int found = 0;<br>+       int wrapuptime = 0;<br>   int ringinuse = q->ringinuse;<br> <br>   const char *config_val;<br>@@ -3363,6 +3386,7 @@<br>        const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);<br>   const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");<br>        const char *paused_str = ast_variable_retrieve(member_config, category, "paused");<br>+ const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");<br> <br>       if (ast_strlen_zero(rt_uniqueid)) {<br>           ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));<br>@@ -3382,6 +3406,13 @@<br>               paused = atoi(paused_str);<br>            if (paused < 0) {<br>                  paused = 0;<br>+          }<br>+    }<br>+<br>+ if (wrapuptime_str) {<br>+                wrapuptime = atoi(wrapuptime_str);<br>+           if (wrapuptime < 0) {<br>+                     wrapuptime = 0;<br>               }<br>     }<br> <br>@@ -3411,6 +3442,7 @@<br>                   }<br>                     m->penalty = penalty;<br>                      m->ringinuse = ringinuse;<br>+                 m->wrapuptime = wrapuptime;<br>                        found = 1;<br>                    ao2_ref(m, -1);<br>                       break;<br>@@ -4343,6 +4375,8 @@<br>  */<br> static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)<br> {<br>+  int wrapuptime;<br>+<br>    if (call->member->paused) {<br>             ast_debug(1, "%s paused, can't receive call\n", call->interface);<br>            return 0;<br>@@ -4353,8 +4387,12 @@<br>             return 0;<br>     }<br> <br>- if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))<br>-             || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {<br>+    if (call->lastqueue) {<br>+            wrapuptime = get_wrapuptime(call->lastqueue, call->member);<br>+    } else {<br>+             wrapuptime = get_wrapuptime(qe->parent, call->member);<br>+ }<br>+    if (wrapuptime && time(NULL) - call->lastcall < wrapuptime) {<br>           ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",<br>                     (call->lastqueue ? call->lastqueue->name : qe->parent->name),<br>                  call->interface);<br>@@ -8554,7 +8592,7 @@<br>                   while ((m = ao2_iterator_next(&mem_iter))) {<br>                              /* Count the agents who are logged in, not paused and not wrapping up */<br>                              if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&<br>-                                             !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {<br>+                                           !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {<br>                                    count++;<br>                              }<br>                             ao2_ref(m, -1);<br>@@ -9098,12 +9136,14 @@<br>      struct member tmpmem;<br>         int penalty;<br>  int ringinuse;<br>+       int wrapuptime;<br>       AST_DECLARE_APP_ARGS(args,<br>            AST_APP_ARG(interface);<br>               AST_APP_ARG(penalty);<br>                 AST_APP_ARG(membername);<br>              AST_APP_ARG(state_interface);<br>                 AST_APP_ARG(ringinuse);<br>+              AST_APP_ARG(wrapuptime);<br>      );<br> <br>         if (ast_strlen_zero(memberdata)) {<br>@@ -9158,11 +9198,23 @@<br>           ringinuse = q->ringinuse;<br>  }<br> <br>+ if (!ast_strlen_zero(args.wrapuptime)) {<br>+             tmp = args.wrapuptime;<br>+               ast_strip(tmp);<br>+              wrapuptime = atoi(tmp);<br>+              if (wrapuptime < 0) {<br>+                     wrapuptime = 0;<br>+              }<br>+    } else {<br>+             wrapuptime = 0;<br>+      }<br>+<br>  /* Find the old position in the list */<br>       ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));<br>       cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);<br> <br>   if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse))) {<br>+            newm->wrapuptime = wrapuptime;<br>             if (cur) {<br>                    /* Round Robin Queue Position must be copied if this is replacing an existing member */<br>                       ao2_lock(q->members);<br>diff --git a/configs/samples/queues.conf.sample b/configs/samples/queues.conf.sample<br>index 3e7cbd8..226a3a9 100644<br>--- a/configs/samples/queues.conf.sample<br>+++ b/configs/samples/queues.conf.sample<br>@@ -551,7 +551,7 @@<br> ; must also preload pbx_config.so and chan_local.so (or pbx_ael.so, pbx_lua.so,<br> ; or pbx_realtime.so, depending on how your dialplan is configured).<br> ;<br>-; syntax: member => interface,[,penalty][,membername][,state_interface][,ringinuse]<br>+; syntax: member => interface,[,penalty][,membername][,state_interface][,ringinuse][,wrapuptime]<br> ;<br> ;member => DAHDI/1<br> ;member => DAHDI/2,10<br>diff --git a/contrib/ast-db-manage/config/versions/e2f04d309071_add_wrapuptime_to_queue_members.py b/contrib/ast-db-manage/config/versions/e2f04d309071_add_wrapuptime_to_queue_members.py<br>new file mode 100644<br>index 0000000..fdb1416<br>--- /dev/null<br>+++ b/contrib/ast-db-manage/config/versions/e2f04d309071_add_wrapuptime_to_queue_members.py<br>@@ -0,0 +1,22 @@<br>+"""add wrapuptime to queue_members<br>+<br>+Revision ID: e2f04d309071<br>+Revises: 041c0d3d1857<br>+Create Date: 2017-12-07 08:32:45.360857<br>+<br>+"""<br>+<br>+# revision identifiers, used by Alembic.<br>+revision = 'e2f04d309071'<br>+down_revision = '041c0d3d1857'<br>+<br>+from alembic import op<br>+import sqlalchemy as sa<br>+<br>+<br>+def upgrade():<br>+    op.add_column('queue_members', sa.Column('wrapuptime', sa.Integer))<br>+<br>+<br>+def downgrade():<br>+    op.drop_column('queue_members', 'wrapuptime')<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/7460">change 7460</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/7460"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I11c85809537f974eb44dc5bbf82bcedd8a458902 </div>
<div style="display:none"> Gerrit-Change-Number: 7460 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: Rodrigo Ramirez Norambuena <a@rodrigoramirez.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Rodrigo Ramirez Norambuena <a@rodrigoramirez.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>