| 142 | При оваа акција за запишување на гласот, повторно е употребен концептот на трансакции бидејќи целта е кога некој гласа истовремено да се забележи и неговата излезност, па така, методот каде се запишува резултатот е анотиран со @Transactional. |
| 143 | {{{#!java |
| 144 | @Override |
| 145 | @Transactional |
| 146 | public CandidacyVote voteForCandidate(Long citizenId, UUID voteIdentificationCodeId, Long realizationId, Long id){ |
| 147 | |
| 148 | Candidacy candidacy = candidacyService.findById(id); |
| 149 | VoteIdentificationCode voteIdentificationCode = voteIdentificationCodeService.findById(voteIdentificationCodeId); |
| 150 | ElectionRealization electionRealization = electionRealizationService.findById(realizationId); |
| 151 | Citizen citizen = citizenService.findById(citizenId); |
| 152 | PollingStation pollingStation = citizen.getAddress().getPollingStation(); |
| 153 | CandidacyVote candidacyVote = new CandidacyVote(); |
| 154 | candidacyVote.setVoteTimestamp(LocalDateTime.now()); |
| 155 | candidacyVote.setVoteIdentificationCode(voteIdentificationCode); |
| 156 | candidacyVote.setElectionRealization(electionRealization); |
| 157 | candidacyVote.setPollingStation(pollingStation); |
| 158 | candidacyVote.pollingStation = pollingStation; |
| 159 | candidacyVote.setCandidacy(candidacy); |
| 160 | |
| 161 | turnoutService.update(null, LocalDateTime.now(), citizenId, realizationId, pollingStation); |
| 162 | |
| 163 | return candidacyVoteRepository.save(candidacyVote); |
| 164 | } |
| 165 | }}} |
| 166 | Соодветно, истата операција во SQL би изгледала вака: |
| 167 | {{{#!sql |
| 168 | DO |
| 169 | $$ |
| 170 | DECLARE |
| 171 | new_gl_id BIGINT; |
| 172 | BEGIN |
| 173 | INSERT INTO glasovi (im_id, ri_id) |
| 174 | VALUES (1, 1) |
| 175 | RETURNING gl_id INTO new_gl_id; |
| 176 | |
| 177 | INSERT INTO glasovi_za_kandidat(gl_id) VALUES (new_gl_id); |
| 178 | |
| 179 | INSERT INTO glasanja (g_id, ri_id, im_id, ug_vreme) VALUES (1, 1, 1, now()); |
| 180 | |
| 181 | COMMIT; |
| 182 | END |
| 183 | $$; |
| 184 | }}} |
| 185 | == Прегледува статистики од излезност по критериуми |
| 186 | На јавната страница /turnout достапни се податоци за процентот на излезност со можност за филтрирање по реализации, општини и/или гласачки места. Имајќи предвид дека се работи за домен каде што бројот на записи, особено во табелата за гласови и излезност ќе биде огромен, решивме овој дел да го имплементираме со материјализиран поглед кој ќе се обноввува на Х време, во нашиот случај 30 минути. На овој начин, наместо да го оптоваруваме Database Engine-от со агрегативни прашалници на секој пристап, податоците ќе се сервираат како готови од погледот. За таа цел е креиран следниот поглед: |
| 187 | {{{#!sql |
| 188 | SELECT row_number() OVER (ORDER BY op.o_ime) AS row_num, |
| 189 | op.o_id, |
| 190 | op.o_ime, |
| 191 | op.map_id, |
| 192 | ri.ri_id, |
| 193 | ri.ri_datum, |
| 194 | ri.ri_ime, |
| 195 | COALESCE((SELECT count(g.g_id)::numeric * 100.0 / count(DISTINCT gr.g_id)::numeric |
| 196 | FROM glasanja g |
| 197 | JOIN realizacii_na_izbori r ON r.ri_id = g.ri_id |
| 198 | LEFT JOIN gragjani gr ON gr.g_id = g.g_id |
| 199 | LEFT JOIN adresi a ON a.a_id = gr.a_id |
| 200 | LEFT JOIN opstini o ON o.o_id = a.o_id |
| 201 | WHERE o.o_id = op.o_id |
| 202 | AND r.ri_id = ri.ri_id |
| 203 | GROUP BY r.ri_id, r.ri_ime, r.ri_datum, o.o_id, o.o_ime), 0::numeric) AS total |
| 204 | FROM opstini op |
| 205 | CROSS JOIN realizacii_na_izbori ri |
| 206 | }}} |
| 207 | Притоа, кога корисникот ќе изврши филтрирање се повикува следниот контролер: |
| 208 | {{{#!java |
| 209 | @GetMapping("/turnout") |
| 210 | public String turnOutResults(Model m, |
| 211 | @RequestParam(required = false, defaultValue = "2") Long realizationId, |
| 212 | @RequestParam(required = false) String opshtinaId, |
| 213 | @RequestParam(required = false) Long izbirachkoMestoId) { |
| 214 | Double turnOut; |
| 215 | if(opshtinaId != null && izbirachkoMestoId != null){ |
| 216 | turnOut = turnoutService.getTurnOutByRealizationAndMunicipalityAndPollingStation(realizationId, opshtinaId, izbirachkoMestoId); |
| 217 | }else if(opshtinaId != null){ |
| 218 | turnOut = turnoutService.getTurnOutByRealizationAndMunicipality(realizationId, opshtinaId); |
| 219 | }else { |
| 220 | turnOut = turnoutService.turnOutByElectionRealization(realizationId); |
| 221 | } |
| 222 | m.addAttribute("replaceTemplate", "turnout_circle"); |
| 223 | m.addAttribute("turnoutPercentage", turnOut); |
| 224 | m.addAttribute("realizationId", realizationId); |
| 225 | m.addAttribute("municipalities", municipalityService.findAll()); |
| 226 | m.addAttribute("realizations", candidatesElectionRealizationService.findAll()); |
| 227 | m.addAttribute("pollingStations", addressService.findAllPollingStations()); |
| 228 | m.addAttribute("realization", candidatesElectionRealizationService.findById(realizationId)); |
| 229 | return "index"; |
| 230 | } |
| 231 | }}} |
| 232 | И приказот кој го добива корисникот е следниот: |
| 233 | == Прегледува вкупни резултати од избори со кандидати/кандидатски листи |
| 234 | |