| | 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 | |