From 5a69899c284fea450a1dab7b1d230eff293cbf50 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Jan 2021 05:49:47 +0000 Subject: [PATCH 1/7] Modify the solver script to take in the number of shifts and the hour shifts as argument. #534 --- utils/schedule_solver/solver.py | 71 +++++++++++++-------------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/utils/schedule_solver/solver.py b/utils/schedule_solver/solver.py index abbdf49d..62a1b059 100644 --- a/utils/schedule_solver/solver.py +++ b/utils/schedule_solver/solver.py @@ -47,48 +47,31 @@ def main(): for hour_index in range(0, len(hours)): req_hours[day_index][hour_index] = int(hours_data[hour_index]) - # index of shift selected is 8 - shift = sys.argv[8] + argv_index = day_index + 2 + # number of days is fixed at 7 so the number of shifts will be in index 8 + num_shifts = sys.argv[argv_index] + hour_shifts = [] - if shift == "24_7": - hour_shifts = [ - ['00 - 09', 0, 1, 2, 3, 4, 5, 6, 7, 8], - ['01 - 10', 1, 2, 3, 4, 5, 6, 7, 8, 9], - ['02 - 11', 2, 3, 4, 5, 6, 7, 8, 9, 10], - ['03 - 12', 3, 4, 5, 6, 7, 8, 9, 10, 11], - ['04 - 13', 4, 5, 6, 7, 8, 9, 10, 11, 12], - ['05 - 14', 5, 6, 7, 8, 9, 10, 11, 12, 13], - ['06 - 15', 6, 7, 8, 9, 10, 11, 12, 13, 14], - ['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16], - ['09 - 18', 9, 10, 11, 12, 13, 14, 15, 16, 17], - ['10 - 19', 10, 11, 12, 13, 14, 15, 16, 17, 18], - ['11 - 20', 11, 12, 13, 14, 15, 16, 17, 18, 19], - ['12 - 21', 12, 13, 14, 15, 16, 17, 18, 19, 20], - ['13 - 22', 13, 14, 15, 16, 17, 18, 19, 20, 21], - ['14 - 23', 14, 15, 16, 17, 18, 19, 20, 21, 22], - ['15 - 00', 15, 16, 17, 18, 19, 20, 21, 22, 23], - ['16 - 01', 16, 17, 18, 19, 20, 21, 22, 23, 0], - ['17 - 02', 17, 18, 19, 20, 21, 22, 23, 0, 1], - ['18 - 03', 18, 19, 20, 21, 22, 23, 0, 1, 2], - ['19 - 04', 19, 20, 21, 22, 23, 0, 1, 2, 3], - ['20 - 05', 20, 21, 22, 23, 0, 1, 2, 3, 4], - ['21 - 06', 21, 22, 23, 0, 1, 2, 3, 4, 5], - ['22 - 07', 22, 23, 0, 1, 2, 3, 4, 5, 6], - ['23 - 08', 23, 0, 1, 2, 3, 4, 5, 6, 7]] - if shift == "8AM_5PM": - hour_shifts = [ - ['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16]] - if shift == "7AM_10PM": - hour_shifts = [ - ['07 - 16', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08 - 17', 8, 9, 10, 11, 12, 13, 14, 15, 16], - ['09 - 18', 9, 10, 11, 12, 13, 14, 15, 16, 17], - ['10 - 19', 10, 11, 12, 13, 14, 15, 16, 17, 18], - ['11 - 20', 11, 12, 13, 14, 15, 16, 17, 18, 19], - ['12 - 21', 12, 13, 14, 15, 16, 17, 18, 19, 20], - ['13 - 22', 13, 14, 15, 16, 17, 18, 19, 20, 21]] + for shift_ctr in range(0, int(num_shifts)): + # form list within the list + hour_shift_item = [] + + # get the shifts from the arguments + shift = sys.argv[argv_index+1] + split_shift = shift.split(',') + + # surround the first item in list with single quotes + shift_index = "\'" + split_shift[0] + "\'" + + # append the first item to the rest of the hour shift informaton + hour_shift = shift_index + ", " + split_shift[1] + ", " + split_shift[2] + ", " + split_shift[3] + ", " + split_shift[4] + ", " + split_shift[5] + ", " + split_shift[6] + ", " + split_shift[7] + ", " + split_shift[8] + ", " + split_shift[9] + + # append to list + hour_shift_item.append(hour_shift) + + # append the list to the list + hour_shifts.append(hour_shift_item) + argv_index+=1 # all possible days riders come in day_shifts = [ @@ -148,11 +131,11 @@ def main(): # solve it! status = solver.Solve() - #print('Number of variables =', solver.NumVariables()) - #print('Number of constraints =', solver.NumConstraints()) + print('Number of variables =', solver.NumVariables()) + print('Number of constraints =', solver.NumConstraints()) if status == solver.OPTIMAL: - #print('Optimal solution found!') + print('Optimal solution found!') for day_index in range(0, len(day_shifts)): for hour_index in range(0, len(hour_shifts)): result = solv_shifts[day_index][hour_index].solution_value() -- 2.43.5 From 1125020d6f296ea68e63117c59240b202327dce8 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Jan 2021 09:36:29 +0000 Subject: [PATCH 2/7] Add ShiftSchedule entity and routes. #534 --- config/acl.yaml | 8 ++ config/menu.yaml | 4 + config/routes/shift_schedule.yaml | 33 ++++++ src/Controller/ShiftScheduleController.php | 5 + src/Entity/ShiftSchedule.php | 129 +++++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 config/routes/shift_schedule.yaml create mode 100644 src/Controller/ShiftScheduleController.php create mode 100644 src/Entity/ShiftSchedule.php diff --git a/config/acl.yaml b/config/acl.yaml index d39b6be3..71a4918a 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -430,6 +430,14 @@ access_keys: label: Menu - id: analytics.forecast label: Forecasting + - id: shift_schedule.list + label: List + - id: shift_schedule.add + label: Add + - id: shift_schedule.update + label: Update + - id: shift_schedule.delete + label: Delete - id: sap_battery label: SAP Battery Access diff --git a/config/menu.yaml b/config/menu.yaml index d90ba3da..67b41bbc 100644 --- a/config/menu.yaml +++ b/config/menu.yaml @@ -216,3 +216,7 @@ main_menu: acl: analytics.forecast label: Forecasting parent: analytics + - id: shift_schedule_list + acl: shift_schedule.list + label: Shift Schedule + parent: analytics diff --git a/config/routes/shift_schedule.yaml b/config/routes/shift_schedule.yaml new file mode 100644 index 00000000..4b1a2d95 --- /dev/null +++ b/config/routes/shift_schedule.yaml @@ -0,0 +1,33 @@ +shift_schedule_list: + path: /shift_schedules + controller: App\Controller\ShiftScheduleController::index + +shift_schedule_rows: + path: /shift_schedules/rows + controller: App\Controller\ShiftScheduleController::rows + methods: [POST] + +shift_schedule_create: + path: /shift_schedules/create + controller: App\Controller\ShiftScheduleController::addForm + methods: [GET] + +shift_schedule_create_submit: + path: /shift_schedules/create + controller: App\Controller\ShiftScheduleController::addSubmit + methods: [POST] + +shift_schedule_update: + path: /shift_schedules/{id} + controller: App\Controller\ShiftScheduleController::updateForm + methods: [GET] + +shift_schedule_update_submit: + path: /shift_schedules/{id} + controller: App\Controller\ShiftScheduleController::updateSubmit + methods: [POST] + +shift_schedule_delete: + path: /shift_schedules/{id} + controller: App\Controller\ShiftScheduleController::destroy + methods: [DELETE] diff --git a/src/Controller/ShiftScheduleController.php b/src/Controller/ShiftScheduleController.php new file mode 100644 index 00000000..b4172ce2 --- /dev/null +++ b/src/Controller/ShiftScheduleController.php @@ -0,0 +1,5 @@ +hour_shifts = []; + } + + public function getID() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getStartTime() + { + return $this->start_time; + } + + public function setStartTime($start_time) + { + $this->start_time = $start_time; + return $this; + } + + public function getEndTime() + { + return $this->end_time; + } + + public function setEndTime($end_time) + { + $this->end_time = $end_time; + return $this; + } + + public function getNumberOfHours() + { + return $this->number_of_hours; + } + + public function setNumberOfHours($number_of_hours) + { + $this->number_of_hours = $number_of_hours; + return $this; + } + + public function addHourShift($id, $value) + { + $this->hour_shifts[$id] = $value; + return $this; + } + + public function getHourShiftsiById($id) + { + // return null if we don't have it + if (!isset($this->hour_shifts[$id])) + return null; + + return $this->hour_shifts[$id]; + } + + public function getHourShifts() + { + return $this->hour_shifts; + } +} -- 2.43.5 From 316ab545e5610ad64b1967697f13fa057312a5c0 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Jan 2021 08:54:46 +0000 Subject: [PATCH 3/7] Add forms for shift schedule. Add saving of shift schedule. #534 --- src/Controller/ShiftScheduleController.php | 211 ++++++++++++++++ src/Entity/ShiftSchedule.php | 40 ++- templates/shift-schedule/.form.html.twig.swo | Bin 0 -> 16384 bytes templates/shift-schedule/form.html.twig | 251 +++++++++++++++++++ templates/shift-schedule/list.html.twig | 155 ++++++++++++ 5 files changed, 633 insertions(+), 24 deletions(-) create mode 100644 templates/shift-schedule/.form.html.twig.swo create mode 100644 templates/shift-schedule/form.html.twig create mode 100644 templates/shift-schedule/list.html.twig diff --git a/src/Controller/ShiftScheduleController.php b/src/Controller/ShiftScheduleController.php index b4172ce2..532089d8 100644 --- a/src/Controller/ShiftScheduleController.php +++ b/src/Controller/ShiftScheduleController.php @@ -2,4 +2,215 @@ namespace App\Controller; +use App\Entity\ShiftSchedule; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Validator\Validator\ValidatorInterface; +use Symfony\Bundle\FrameworkBundle\Controller\Controller; + +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; + +use Catalyst\MenuBundle\Annotation\Menu; + +use DateTime; + +class ShiftScheduleController extends Controller +{ + /** + * @Menu(selected="shift_schedule_list") + */ + public function index() + { + $this->denyAccessUnlessGranted('shift_schedule.list', null, 'No access.'); + + return $this->render('shift-schedule/list.html.twig'); + } + + public function rows(Request $req) + { + $this->denyAccessUnlessGranted('shift_schedule.list', null, 'No access.'); + + // get query builder + $qb = $this->getDoctrine() + ->getRepository(ShiftSchedule::class) + ->createQueryBuilder('q'); + + // get datatable params + $datatable = $req->request->get('datatable'); + + // count total records + $tquery = $qb->select('COUNT(q)'); + $this->setQueryFilters($datatable, $tquery); + $total = $tquery->getQuery() + ->getSingleScalarResult(); + + // get current page number + $page = $datatable['pagination']['page'] ?? 1; + + $perpage = $datatable['pagination']['perpage']; + $offset = ($page - 1) * $perpage; + + // add metadata + $meta = [ + 'page' => $page, + 'perpage' => $perpage, + 'pages' => ceil($total / $perpage), + 'total' => $total, + 'sort' => 'asc', + 'field' => 'id' + ]; + + // build query + $query = $qb->select('q'); + $this->setQueryFilters($datatable, $query); + + // check if sorting is present, otherwise use default + if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) { + $order = $datatable['sort']['sort'] ?? 'asc'; + $query->orderBy('q.' . $datatable['sort']['field'], $order); + } else { + $query->orderBy('q.id', 'asc'); + } + + // get rows for this page + $obj_rows = $query->setFirstResult($offset) + ->setMaxResults($perpage) + ->getQuery() + ->getResult(); + + // process rows + $rows = []; + foreach ($obj_rows as $orow) { + // add row data + $shifts = $orow->getHourShifts(); + $hour_shifts = []; + foreach ($shifts as $shift) + { + $hour_shifts[] = [ + $shift['start'] . ' - ' . $shift['end'] + ]; + } + + $row['id'] = $orow->getID(); + $row['name'] = $orow->getName(); + $row['start_time'] = $orow->getStartTime()->format('g:i A'); + $row['end_time'] = $orow->getEndtime()->format('g:i A'); + $row['hour_shifts'] = $hour_shifts; + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('shift_schedule.update')) + $row['meta']['update_url'] = $this->generateUrl('shift_schedule_update', ['id' => $row['id']]); + if ($this->isGranted('shift_schedule.delete')) + $row['meta']['delete_url'] = $this->generateUrl('shift_schedule_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + /** + * @Menu(selected="shift_schedule_list") + */ + public function addForm() + { + $this->denyAccessUnlessGranted('shift_schedule.add', null, 'No access.'); + + $params = []; + $params['obj'] = new ShiftSchedule(); + $params['mode'] = 'create'; + + // response + return $this->render('shift-schedule/form.html.twig', $params); + } + + public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator) + { + $this->denyAccessUnlessGranted('shift_schedule.add', null, 'No access.'); + + $obj = new ShiftSchedule(); + + // set and save values + $this->setObject($obj, $em, $req); + + // validate + $errors = $validator->validate($obj); + + // initialize error list + $error_array = []; + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // validated! save the entity + $em->persist($obj); + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } + + protected function setObject(ShiftSchedule $obj, EntityManagerInterface $em, Request $req) + { + $name = $req->request->get('name'); + + // times + $format = 'g:i A'; + $start_time = DateTime::createFromFormat($format, $req->request->get('start_time')); + $end_time = DateTime::createFromFormat($format, $req->request->get('end_time')); + + // get the shift entries + $shift_start = $req->request->get('shift_start_time'); + $shift_end = $req->request->get('shift_end_time'); + + $shifts = []; + for ($i = 0; $i < count($shift_start); $i++) + { + $shifts[] = [ + 'start' => $shift_start[$i], + 'end' => $shift_end[$i] + ]; + } + + $obj->setName($name) + ->setStartTime($start_time) + ->setEndTime($end_time) + ->setHourShifts($shifts); + } + +} diff --git a/src/Entity/ShiftSchedule.php b/src/Entity/ShiftSchedule.php index 7f73b2eb..1cdf7896 100644 --- a/src/Entity/ShiftSchedule.php +++ b/src/Entity/ShiftSchedule.php @@ -5,6 +5,8 @@ namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; +use DateTime; + /** * @ORM\Entity * @ORM\Table(name="shift_schedule") @@ -28,26 +30,19 @@ class ShiftSchedule // start time /** - * @ORM\Column(type="string", nullable=true) + * @ORM\Column(type="time") * @Assert\NotBlank() */ protected $start_time; // end time /** - * @ORM\(Column(type="string", nullable=true) + * @ORM\Column(type="time") * @Assert\NotBlank() */ protected $end_time; - // number of hours in a shift - /** - * @ORM\(Column(type="integer") - * @Assert\NotBlank() - */ - protected $number_of_hours; - - // hours + // hour shifts /** * @ORM\Column(type="json") */ @@ -55,6 +50,8 @@ class ShiftSchedule public function __construct() { + $this->start_time = new DateTime(); + $this->end_time = new DateTime(); $this->hour_shifts = []; } @@ -79,7 +76,7 @@ class ShiftSchedule return $this->start_time; } - public function setStartTime($start_time) + public function setStartTime(DateTime $start_time) { $this->start_time = $start_time; return $this; @@ -90,30 +87,19 @@ class ShiftSchedule return $this->end_time; } - public function setEndTime($end_time) + public function setEndTime(DateTime $end_time) { $this->end_time = $end_time; return $this; } - public function getNumberOfHours() - { - return $this->number_of_hours; - } - - public function setNumberOfHours($number_of_hours) - { - $this->number_of_hours = $number_of_hours; - return $this; - } - public function addHourShift($id, $value) { $this->hour_shifts[$id] = $value; return $this; } - public function getHourShiftsiById($id) + public function getHourShiftsById($id) { // return null if we don't have it if (!isset($this->hour_shifts[$id])) @@ -126,4 +112,10 @@ class ShiftSchedule { return $this->hour_shifts; } + + public function setHourShifts(array $hour_shifts) + { + $this->hour_shifts = $hour_shifts; + return $this; + } } diff --git a/templates/shift-schedule/.form.html.twig.swo b/templates/shift-schedule/.form.html.twig.swo new file mode 100644 index 0000000000000000000000000000000000000000..26da1a746f8ae108ddaa2d699d62d2c4721101bd GIT binary patch literal 16384 zcmeHOO^6&t6fRBFsEL|*$U%k5m^d?JYkD^;3ghgGF>4Isifjys$XMN7Gt+KQSEsvX zcjLNv_9i9>Cg4Tzq=D!}@(GGpCL~O+^uc27%w1nI7h1HNzyV6o^zoM4C=18qZz%XDK7>|J+Wct9= zq?Wz2u!r8d>xuE287aenVZbn87%&VN1`Gp+0mFb{;EG^CgGHFkl!k3>XFs1BL;^fMLKe zU>Nuh7~n1;w?Xe=ec;FY|L*zzhnopG3w#ND0Gt6N@Hns&xElEFCPID%z6U-9-T+<# zLZAw42fp4x$Sc4xU^j4nJM;moz(L^m8wvRecok>^j{p}2I6^A?+PgXamdDQWF9M2SdPJPZC zUpk9S7G`UfH=dT7HrQ3-1z|_AW+Xcyn@s(VcI#jsLKlu`^V$LVkz`O!GiXMU4SkLdrH&YRbqpHJ2h z!nL`xNL!wZDR;TztlKh=?&nl7Pvj zy1Wk!3t^qn^r7P&n3@vs-uqKN1 ze%gurQZe}~wBG$Jw4T=1Gg_pOn^y3MZV#WG#cAJ5W-?Bm&y&9n(W7UNo| z#cl5Uv%S4k8gtk>VQo#SMq1PzpL0F*v9G6eWJ7cnRBZ5$5!}>T)7>kvFq;JZ4Y+Q!yb5(z|$P+a*1$FN9Q4SFVS{bJBNol z6gO!(q}71*rjkeoSwdl~Ep4x_clj1N;jQ>=>OiJ7Ux!4~y}O68gQDpL)#?H^{^&Ae zvm`H@o*+b^(4q!uIyZl)N*6k|=0`*{k?*Zj17SOGnb4j0B_y6yPaXT!gzA2Wj%!vv z#``)JG2T%)l99nlbXmg}D>O}%9zKbWnS%i&%YB~)wr;*VxPx4ow^B>h2 zTn9PP0l%VO_8;Q1D5?yf~GnWTV5e+ozH=ByUP+#M|XUP3p8l50H#M89F zTolPDE|uvj(Veoa>^_dhJ{7t$eX67Xo4FRyROnw_@_#4SME{#FYZG*8ax&K>UkP@l z?;n+66 +
+
+
+

Shift Schedules

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ {% if mode == 'update' %} + Edit Shift Schedule + {{ obj.getName() }} + {% else %} + New Shift Schedule + {% endif %} +

+
+
+
+
+
+
+
+ + + +
+
+
+
+ +
+ + + + +
+ +
+
+ +
+ + + + +
+ +
+
+
+
+
+

+ Breakdown of Shift Schedule +

+
+
+ +
+
+
+
+ + + + +
+
+
+
+ + + + +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ + Back +
+
+
+
+ +
+ +{% endblock %} + + +{% block scripts %} + +{% endblock %} diff --git a/templates/shift-schedule/list.html.twig b/templates/shift-schedule/list.html.twig new file mode 100644 index 00000000..ecb8a05f --- /dev/null +++ b/templates/shift-schedule/list.html.twig @@ -0,0 +1,155 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Shift Schedules +

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} -- 2.43.5 From ba5d7d364d2706a669c200a46b7aaf258b457886 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Jan 2021 10:39:27 +0000 Subject: [PATCH 4/7] Add update of shift schedule. #534 --- src/Controller/ShiftScheduleController.php | 101 ++++++++++++++++++++- templates/shift-schedule/form.html.twig | 41 +++++---- 2 files changed, 119 insertions(+), 23 deletions(-) diff --git a/src/Controller/ShiftScheduleController.php b/src/Controller/ShiftScheduleController.php index 532089d8..23ba1a76 100644 --- a/src/Controller/ShiftScheduleController.php +++ b/src/Controller/ShiftScheduleController.php @@ -90,8 +90,12 @@ class ShiftScheduleController extends Controller $hour_shifts = []; foreach ($shifts as $shift) { + // convert to DateTime then format + $shift_start = DateTime::createFromFormat('H:i', $shift['start']); + $shift_end = DateTime::createFromFormat('H:i', $shift['end']); + $hour_shifts[] = [ - $shift['start'] . ' - ' . $shift['end'] + $shift_start->format('g:i A') . ' - ' . $shift_end->format('g:i A') ]; } @@ -133,6 +137,7 @@ class ShiftScheduleController extends Controller $params = []; $params['obj'] = new ShiftSchedule(); $params['mode'] = 'create'; + $params['shift_entries'] = []; // response return $this->render('shift-schedule/form.html.twig', $params); @@ -177,6 +182,87 @@ class ShiftScheduleController extends Controller ]); } + /** + * @Menu(selected="shift_schedule_list") + */ + public function updateForm($id, EntityManagerInterface $em) + { + $this->denyAccessUnlessGranted('shift_schedule.update', null, 'No access.'); + + $params = []; + + // find shift schedule + $obj = $em->getRepository(ShiftSchedule::class)->find($id); + + // make sure this row exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + // get the shift entries + $shifts = $obj->getHourShifts(); + $hour_shifts = []; + foreach ($shifts as $shift) + { + // convert to DateTime then format + $shift_start = DateTime::createFromFormat('H:i', $shift['start']); + $shift_end = DateTime::createFromFormat('H:i', $shift['end']); + + $hour_shifts[] = [ + 'start' => $shift_start, + 'end' => $shift_end + ]; + } + + $params['obj'] = $obj; + $params['mode'] = 'update'; + $params['shift_entries'] = $hour_shifts; + + // response + return $this->render('shift-schedule/form.html.twig', $params); + } + + public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, $id) + { + $this->denyAccessUnlessGranted('shift_schedule.update', null, 'No access.'); + + // get object + $obj = $em->getRepository(ShiftSchedule::class)->find($id); + + // make sure this object exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + $this->setObject($obj, $em, $req); + + // validate + $errors = $validator->validate($obj); + + // initialize error list + $error_array = []; + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // validated! save the entity + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + protected function setQueryFilters($datatable, QueryBuilder $query) { if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { @@ -190,7 +276,7 @@ class ShiftScheduleController extends Controller $name = $req->request->get('name'); // times - $format = 'g:i A'; + $format = 'h:i A'; $start_time = DateTime::createFromFormat($format, $req->request->get('start_time')); $end_time = DateTime::createFromFormat($format, $req->request->get('end_time')); @@ -201,9 +287,16 @@ class ShiftScheduleController extends Controller $shifts = []; for ($i = 0; $i < count($shift_start); $i++) { + // convert to DateTime so that we can reformat to 00-23 format + $s_start = DateTime::createFromFormat($format, $shift_start[$i]); + $e_start = DateTime::createFromFormat($format, $shift_end[$i]); + + $start = $s_start->format('H:00'); + $end = $e_start->format('H:00'); + $shifts[] = [ - 'start' => $shift_start[$i], - 'end' => $shift_end[$i] + 'start' => $start, + 'end' => $end ]; } diff --git a/templates/shift-schedule/form.html.twig b/templates/shift-schedule/form.html.twig index d39432c6..34629fd4 100644 --- a/templates/shift-schedule/form.html.twig +++ b/templates/shift-schedule/form.html.twig @@ -79,27 +79,30 @@
-
-
-
- - - - + + {% for shift_entry in shift_entries %} +
+
+
+ + + + +
+
+
+
+ + + + +
+
+
+
-
-
- - - - -
-
-
- -
-
+ {% endfor %}
-- 2.43.5 From d07a9461fb7e24e212e65869af443418666d8f57 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Jan 2021 10:43:53 +0000 Subject: [PATCH 5/7] Delete swap file. #534 --- templates/shift-schedule/.form.html.twig.swo | Bin 16384 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 templates/shift-schedule/.form.html.twig.swo diff --git a/templates/shift-schedule/.form.html.twig.swo b/templates/shift-schedule/.form.html.twig.swo deleted file mode 100644 index 26da1a746f8ae108ddaa2d699d62d2c4721101bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHOO^6&t6fRBFsEL|*$U%k5m^d?JYkD^;3ghgGF>4Isifjys$XMN7Gt+KQSEsvX zcjLNv_9i9>Cg4Tzq=D!}@(GGpCL~O+^uc27%w1nI7h1HNzyV6o^zoM4C=18qZz%XDK7>|J+Wct9= zq?Wz2u!r8d>xuE287aenVZbn87%&VN1`Gp+0mFb{;EG^CgGHFkl!k3>XFs1BL;^fMLKe zU>Nuh7~n1;w?Xe=ec;FY|L*zzhnopG3w#ND0Gt6N@Hns&xElEFCPID%z6U-9-T+<# zLZAw42fp4x$Sc4xU^j4nJM;moz(L^m8wvRecok>^j{p}2I6^A?+PgXamdDQWF9M2SdPJPZC zUpk9S7G`UfH=dT7HrQ3-1z|_AW+Xcyn@s(VcI#jsLKlu`^V$LVkz`O!GiXMU4SkLdrH&YRbqpHJ2h z!nL`xNL!wZDR;TztlKh=?&nl7Pvj zy1Wk!3t^qn^r7P&n3@vs-uqKN1 ze%gurQZe}~wBG$Jw4T=1Gg_pOn^y3MZV#WG#cAJ5W-?Bm&y&9n(W7UNo| z#cl5Uv%S4k8gtk>VQo#SMq1PzpL0F*v9G6eWJ7cnRBZ5$5!}>T)7>kvFq;JZ4Y+Q!yb5(z|$P+a*1$FN9Q4SFVS{bJBNol z6gO!(q}71*rjkeoSwdl~Ep4x_clj1N;jQ>=>OiJ7Ux!4~y}O68gQDpL)#?H^{^&Ae zvm`H@o*+b^(4q!uIyZl)N*6k|=0`*{k?*Zj17SOGnb4j0B_y6yPaXT!gzA2Wj%!vv z#``)JG2T%)l99nlbXmg}D>O}%9zKbWnS%i&%YB~)wr;*VxPx4ow^B>h2 zTn9PP0l%VO_8;Q1D5?yf~GnWTV5e+ozH=ByUP+#M|XUP3p8l50H#M89F zTolPDE|uvj(Veoa>^_dhJ{7t$eX67Xo4FRyROnw_@_#4SME{#FYZG*8ax&K>UkP@l z?;n+66 Date: Mon, 1 Feb 2021 03:20:23 +0000 Subject: [PATCH 6/7] Add delete for shift schedule. #534 --- src/Controller/ShiftScheduleController.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Controller/ShiftScheduleController.php b/src/Controller/ShiftScheduleController.php index 23ba1a76..0c5c2e8d 100644 --- a/src/Controller/ShiftScheduleController.php +++ b/src/Controller/ShiftScheduleController.php @@ -263,6 +263,26 @@ class ShiftScheduleController extends Controller ]); } + public function destroy($id, EntityManagerInterface $em) + { + $this->denyAccessUnlessGranted('shift_schedule.delete', null, 'No access.'); + + // get object data + $obj = $em->getRepository(ShiftSchedule::class)->find($id); + + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + // delete this object + $em->remove($obj); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } + protected function setQueryFilters($datatable, QueryBuilder $query) { if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { -- 2.43.5 From e306b5931ddb8d195aedd56f9f92cca1aed701dc Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 1 Feb 2021 09:33:19 +0000 Subject: [PATCH 7/7] Modify the hours_shift arguments for the script. Populate the hours shift array using selected schedule. #534 --- src/Controller/AnalyticsController.php | 140 +++++++++++++++---------- utils/schedule_solver/solver.py | 16 +-- 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/src/Controller/AnalyticsController.php b/src/Controller/AnalyticsController.php index d18b10bb..68e703ed 100644 --- a/src/Controller/AnalyticsController.php +++ b/src/Controller/AnalyticsController.php @@ -21,8 +21,7 @@ use DateInterval; use App\Entity\JobOrder; use App\Entity\Hub; - -use App\Ramcar\ShiftSchedule; +use App\Entity\ShiftSchedule; class AnalyticsController extends Controller { @@ -93,10 +92,19 @@ class AnalyticsController extends Controller $hub_list[$hub->getID()] = $hub->getName() . ' - ' . $hub->getBranch(); } + // get saved shift schedules + $all_shift_schedules = $em->getRepository(ShiftSchedule::class)->findAll(); + + $shift_sched_list = []; + foreach ($all_shift_schedules as $sched) + { + $shift_sched_list[$sched->getID()] = $sched->getName(); + } + $params = [ 'hub_list' => $hub_list, 'default_hubs' => $hub_ids, - 'shift_schedules' => ShiftSchedule::getCollection(), + 'shift_schedules' => $shift_sched_list, ]; return $this->render('analytics/forecast_form.html.twig', $params); @@ -123,8 +131,9 @@ class AnalyticsController extends Controller $shift = $req->request->get('shift_schedule'); // TODO: populate the hour_shift array, depending on the shift selected - $hour_shifts = $this->populateHourShift($shift); + $hour_shifts = $this->populateHourShift($em, $shift); + error_log('reference'); error_log(print_r($hour_shifts, true)); // error_log(print_r($hub_list, true)); @@ -177,7 +186,7 @@ class AnalyticsController extends Controller // error_log(print_r($scheduler_data, true)); // run scheduler - $sched_res = $this->runScheduler($scheduler_data, $hour_shifts, $shift); + $sched_res = $this->runScheduler($scheduler_data, $hour_shifts); // tally total JOs for the month foreach ($scheduler_data as $sday_data) @@ -252,7 +261,7 @@ class AnalyticsController extends Controller return $day_data; } - protected function runScheduler($scheduler_data, $hour_shifts, $shift) + protected function runScheduler($scheduler_data, $hour_shifts) { // run python script to solve scheduling for riders @@ -267,8 +276,37 @@ class AnalyticsController extends Controller foreach ($scheduler_data as $weekday_data) $args[] = implode('-', $weekday_data); - // add shift - $args[] = $shift; + // add length of hour_shifts + $args[] = count($hour_shifts); + + // form hour_shifts argument for the python script + foreach ($hour_shifts as $hour_shift) + { + $shift = ''; + foreach ($hour_shift as $entry) + { + // check if entry has format '00:00 - 00:00' + if (strpos($entry, ':')) + { + // need to modify to 00 - 00 + $hours = explode('-', $entry); + $start = trim($hours[0]); + $end = trim($hours[1]); + + // get the hour only + $s_parts = explode(':', $start); + $e_parts = explode(':', $end); + $start_hour = trim($s_parts[0]); + $end_hour = trim($s_parts[1]); + + $shift = '\'' . $start_hour . ' - ' . $end_hour . '\''; + } + else + $shift = $shift . ',' . $entry; + } + + $args[] = $shift; + } //error_log(print_r($args, true)); @@ -676,55 +714,51 @@ class AnalyticsController extends Controller { } - protected function populateHourShift($shift) + protected function populateHourShift(EntityManagerInterface $em, $id) { $hour_shift = []; - if ($shift == '24_7') { - $hour_shift = [ - ['00:00 - 09:00', 0, 1, 2, 3, 4, 5, 6, 7, 8], - ['01:00 - 10:00', 1, 2, 3, 4, 5, 6, 7, 8, 9], - ['02:00 - 11:00', 2, 3, 4, 5, 6, 7, 8, 9, 10], - ['03:00 - 12:00', 3, 4, 5, 6, 7, 8, 9, 10, 11], - ['04:00 - 13:00', 4, 5, 6, 7, 8, 9, 10, 11, 12], - ['05:00 - 14:00', 5, 6, 7, 8, 9, 10, 11, 12, 13], - ['06:00 - 15:00', 6, 7, 8, 9, 10, 11, 12, 13, 14], - ['07:00 - 16:00', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08:00 - 17:00', 8, 9, 10, 11, 12, 13, 14, 15, 16], - ['09:00 - 18:00', 9, 10, 11, 12, 13, 14, 15, 16, 17], - ['10:00 - 19:00', 10, 11, 12, 13, 14, 15, 16, 17, 18], - ['11:00 - 20:00', 11, 12, 13, 14, 15, 16, 17, 18, 19], - ['12:00 - 21:00', 12, 13, 14, 15, 16, 17, 18, 19, 20], - ['13:00 - 22:00', 13, 14, 15, 16, 17, 18, 19, 20, 21], - ['14:00 - 23:00', 14, 15, 16, 17, 18, 19, 20, 21, 22], - ['15:00 - 00:00', 15, 16, 17, 18, 19, 20, 21, 22, 23], - ['16:00 - 01:00', 16, 17, 18, 19, 20, 21, 22, 23, 0], - ['17:00 - 02:00', 17, 18, 19, 20, 21, 22, 23, 0, 1], - ['18:00 - 03:00', 18, 19, 20, 21, 22, 23, 0, 1, 2], - ['19:00 - 04:00', 19, 20, 21, 22, 23, 0, 1, 2, 3], - ['20:00 - 05:00', 20, 21, 22, 23, 0, 1, 2, 3, 4], - ['21:00 - 06:00', 21, 22, 23, 0, 1, 2, 3, 4, 5], - ['22:00 - 07:00', 22, 23, 0, 1, 2, 3, 4, 5, 6], - ['23:00 - 08:00', 23, 0, 1, 2, 3, 4, 5, 6, 7], - ]; - } - if ($shift == '8AM_5PM') { - $hour_shift = [ - ['07:00 - 16:00', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08:00 - 17:00', 8, 9, 10, 11, 12, 13, 14, 15, 16], - ]; - } + // get the hour shifts for the selected shift scheduled + $shift = $em->getRepository(ShiftSchedule::class)->find($id); - if ($shift == '7AM_10PM') { - $hour_shift = [ - ['07:00 - 16:00', 7, 8, 9, 10, 11, 12, 13, 14, 15], - ['08:00 - 17:00', 8, 9, 10, 11, 12, 13, 14, 15, 16], - ['09:00 - 18:00', 9, 10, 11, 12, 13, 14, 15, 16, 17], - ['10:00 - 19:00', 10, 11, 12, 13, 14, 15, 16, 17, 18], - ['11:00 - 20:00', 11, 12, 13, 14, 15, 16, 17, 18, 19], - ['12:00 - 21:00', 12, 13, 14, 15, 16, 17, 18, 19, 20], - ['13:00 - 22:00', 13, 14, 15, 16, 17, 18, 19, 20, 21] - ]; + if (empty($shift)) + throw $this->createNotFoundException('The item does not exist'); + + $shifts = $shift->getHourShifts(); + + foreach ($shifts as $shift) + { + $shift_entry = []; + // format of hour_shift: [['start time - end time', start time, ... , end time - 1]] + // first hour of hour shift is the start time + // form the first entry of the hour shift + $shift_time = $shift['start'] . ' - ' . $shift['end']; + + $shift_entry[] = $shift_time; + + $s_times = explode(':', $shift['start']); + $e_times = explode(':', $shift['end']); + + $shift_start = intval($s_times[0]); + $shift_end = intval($e_times[0]); + + if ($shift_start == 23) + { + $shift_entry[] = 23; + for ($hour = 0; $hour < $shift_end; $hour++) + { + $shift_entry[] = $hour; + } + } + for($hour = $shift_start; $hour < $shift_end; $hour++) + { + $shift_entry[] = $hour; + + if ($hour == 23) + $hour = 0; + } + + $hour_shift[] = $shift_entry; } return $hour_shift; diff --git a/utils/schedule_solver/solver.py b/utils/schedule_solver/solver.py index 62a1b059..aa49d70c 100644 --- a/utils/schedule_solver/solver.py +++ b/utils/schedule_solver/solver.py @@ -56,18 +56,10 @@ def main(): # form list within the list hour_shift_item = [] - # get the shifts from the arguments shift = sys.argv[argv_index+1] - split_shift = shift.split(',') - - # surround the first item in list with single quotes - shift_index = "\'" + split_shift[0] + "\'" - - # append the first item to the rest of the hour shift informaton - hour_shift = shift_index + ", " + split_shift[1] + ", " + split_shift[2] + ", " + split_shift[3] + ", " + split_shift[4] + ", " + split_shift[5] + ", " + split_shift[6] + ", " + split_shift[7] + ", " + split_shift[8] + ", " + split_shift[9] # append to list - hour_shift_item.append(hour_shift) + hour_shift_item.append(shift) # append the list to the list hour_shifts.append(hour_shift_item) @@ -131,11 +123,11 @@ def main(): # solve it! status = solver.Solve() - print('Number of variables =', solver.NumVariables()) - print('Number of constraints =', solver.NumConstraints()) + #print('Number of variables =', solver.NumVariables()) + #print('Number of constraints =', solver.NumConstraints()) if status == solver.OPTIMAL: - print('Optimal solution found!') + #print('Optimal solution found!') for day_index in range(0, len(day_shifts)): for hour_index in range(0, len(hour_shifts)): result = solv_shifts[day_index][hour_index].solution_value() -- 2.43.5