se agregaron las firmas y los campos del practicante para adaptarse al estandar FHIR

This commit is contained in:
luc662 2025-05-22 22:57:25 +00:00
parent fbbc996b82
commit 9f8addf510
8 changed files with 186 additions and 92 deletions

View file

@ -29,6 +29,9 @@ type Receta struct {
FechaDeAutorizacion string `json:"fechaDeAutorizacion"` FechaDeAutorizacion string `json:"fechaDeAutorizacion"`
Cantidad string `json:"cantidad"` Cantidad string `json:"cantidad"`
ExpectedSupplyDuration string `json:"expectedSupplyDuration"` ExpectedSupplyDuration string `json:"expectedSupplyDuration"`
Practitioner string `json:"practitioner"`
PractitionerDocumentNumber string `json:"practitionerDocumentNumber"`
Signature string `json:"signature"`
} }
type Vacuna struct { type Vacuna struct {
@ -44,9 +47,10 @@ type Vacuna struct {
ExpirationDate string `json:"expirationDate"` // como string ISO8601 ExpirationDate string `json:"expirationDate"` // como string ISO8601
PatientDocumentNumber string `json:"patientDocumentNumber"` PatientDocumentNumber string `json:"patientDocumentNumber"`
Reactions string `json:"reactions"` // puede ser un string o una estructura si querés después Reactions string `json:"reactions"` // puede ser un string o una estructura si querés después
Practitioner string `json:"practitioner"`
PractitionerDocumentNumber string `json:"practitionerDocumentNumber"`
} }
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error { func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
recetas := []Receta{ recetas := []Receta{
{ {
@ -67,6 +71,9 @@ func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface)
FechaDeAutorizacion: "2024-01-01T09:00:00Z", FechaDeAutorizacion: "2024-01-01T09:00:00Z",
Cantidad: "5", Cantidad: "5",
ExpectedSupplyDuration: "2024-02-01T09:00:00Z", ExpectedSupplyDuration: "2024-02-01T09:00:00Z",
Practitioner: "practitioner",
PractitionerDocumentNumber: "123456789",
Signature: "signature",
}, },
{ {
ID: "receta2", ID: "receta2",
@ -86,6 +93,9 @@ func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface)
FechaDeAutorizacion: "2024-01-10T10:00:00Z", FechaDeAutorizacion: "2024-01-10T10:00:00Z",
Cantidad: "10", Cantidad: "10",
ExpectedSupplyDuration: "2024-04-10T10:00:00Z", ExpectedSupplyDuration: "2024-04-10T10:00:00Z",
Practitioner: "practitioner",
PractitionerDocumentNumber: "123456789",
Signature: "signature",
}, },
} }
@ -121,6 +131,39 @@ func (s *SmartContract) CreateReceta(ctx contractapi.TransactionContextInterface
return ctx.GetStub().PutState(receta.ID, recetaJSON) return ctx.GetStub().PutState(receta.ID, recetaJSON)
} }
func (s *SmartContract) FirmarReceta(ctx contractapi.TransactionContextInterface, recetaID string, firma string) error {
exists, err := s.RecetaExists(ctx, recetaID)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("la receta %s no existe", recetaID)
}
recetaJSON, err := ctx.GetStub().GetState(recetaID)
if err != nil {
return fmt.Errorf("error al obtener la receta: %v", err)
}
if recetaJSON == nil {
return fmt.Errorf("la receta %s no fue encontrada en el ledger", recetaID)
}
var receta Receta
if err := json.Unmarshal(recetaJSON, &receta); err != nil {
return fmt.Errorf("error al parsear la receta: %v", err)
}
if receta.Status != "draft" {
return fmt.Errorf("la receta %s no puede ser firmada porque no está en estado 'draft'", recetaID)
}
receta.Signature = firma
receta.Status = "active"
receta.StatusChange = "FIRMADA"
updatedRecetaJSON, err := json.Marshal(receta)
if err != nil {
return fmt.Errorf("error al serializar la receta firmada: %v", err)
}
return ctx.GetStub().PutState(recetaID, updatedRecetaJSON)
}
func (s *SmartContract) EntregarReceta(ctx contractapi.TransactionContextInterface, recetaID string) error { func (s *SmartContract) EntregarReceta(ctx contractapi.TransactionContextInterface, recetaID string) error {
exists, err := s.RecetaExists(ctx, recetaID) exists, err := s.RecetaExists(ctx, recetaID)
if err != nil { if err != nil {
@ -144,13 +187,12 @@ func (s *SmartContract) EntregarReceta(ctx contractapi.TransactionContextInterfa
return fmt.Errorf("error al parsear la receta actual: %v", err) return fmt.Errorf("error al parsear la receta actual: %v", err)
} }
// Validar que el estado actual sea ACTIVO if recetaActual.Status != "active" {
if recetaActual.Status != "ACTIVO" { return fmt.Errorf("solo se puede entregar la receta si está en estado 'active'")
return fmt.Errorf("solo se puede entregar la receta si está en estado 'ACTIVO'")
} }
// Cambiar el estado a ENTREGADO // Cambiar el estado a ENTREGADO
recetaActual.Status = "ENTREGADO" recetaActual.Status = "completed"
// Guardar la receta modificada // Guardar la receta modificada
updatedRecetaJSON, err := json.Marshal(recetaActual) updatedRecetaJSON, err := json.Marshal(recetaActual)
@ -260,12 +302,13 @@ func (s *SmartContract) GetMultipleRecetas(ctx contractapi.TransactionContextInt
var receta Receta var receta Receta
err = json.Unmarshal(recetaJSON, &receta) err = json.Unmarshal(recetaJSON, &receta)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("error al parsear la receta con ID %s: %v", id, err)
} }
recetas = append(recetas, &receta) recetas = append(recetas, &receta)
} }
return recetas, nil return recetas, nil
} }
// TODO: adaptar los campos para que se tengan un identificar de usuarios ademas del DNI // TODO: adaptar los campos para que se tengan un identificar de usuarios ademas del DNI
func (s *SmartContract) GetRecetasPorDniYEstado(ctx contractapi.TransactionContextInterface, dni string, estado string) ([]*Receta, error) { func (s *SmartContract) GetRecetasPorDniYEstado(ctx contractapi.TransactionContextInterface, dni string, estado string) ([]*Receta, error) {
if dni == "" || estado == "" { if dni == "" || estado == "" {

View file

@ -92,13 +92,21 @@ public class RecetaController {
return new ResponseEntity<>(recetaDto, HttpStatus.OK); return new ResponseEntity<>(recetaDto, HttpStatus.OK);
} catch (IOException e) { } catch (IOException e) {
logger.error("IOException occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log de excepción específica logger.error("IOException occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log de
// excepción
// específica
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE); return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
} catch (GatewayException e) { } catch (GatewayException e) {
logger.error("GatewayException occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log de excepción Gateway logger.error("GatewayException occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log
// de
// excepción
// Gateway
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE); return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
} catch (Exception e) { } catch (Exception e) {
logger.error("Unexpected error occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log de error inesperado logger.error("Unexpected error occurred while obtaining receta with ID: {}", requestBody.getId(), e); // Log
// de
// error
// inesperado
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} }
} }
@ -147,6 +155,29 @@ public class RecetaController {
} }
} }
@PutMapping("/firmar")
public ResponseEntity<Void> firmarReceta(@RequestBody Map<String, String> requestBody) {
try {
String id = requestBody.get("id");
String signature = requestBody.get("signature");
if (id == null || id.isEmpty()) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
System.out.println("\n--> Submit Transaction: FirmarReceta");
recetaService.firmarReceta(id, signature);
return new ResponseEntity<>(HttpStatus.OK);
} catch (EndorseException | SubmitException | CommitStatusException | CommitException e) {
e.printStackTrace(); // o algún log específico
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} catch (GatewayException e) {
e.printStackTrace(); // este bloque rara vez se ejecutaría si ya atrapás las anteriores
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private RecetaDto mapToDto(Receta receta) { private RecetaDto mapToDto(Receta receta) {
RecetaDto dto = new RecetaDto(); RecetaDto dto = new RecetaDto();
dto.setIdentifier(receta.getIdentifier()); dto.setIdentifier(receta.getIdentifier());
@ -165,6 +196,9 @@ public class RecetaController {
dto.setFechaDeAutorizacion(receta.getFechaDeAutorizacion()); dto.setFechaDeAutorizacion(receta.getFechaDeAutorizacion());
dto.setCantidad(receta.getCantidad()); dto.setCantidad(receta.getCantidad());
dto.setExpectedSupplyDuration(receta.getExpectedSupplyDuration()); dto.setExpectedSupplyDuration(receta.getExpectedSupplyDuration());
dto.setPractitioner(receta.getPractitioner());
dto.setPractitionerDocumentNumber(receta.getPractitionerDocumentNumber());
dto.setSignature(receta.setSignature());
return dto; return dto;
} }
} }

View file

@ -157,6 +157,8 @@ public class VacunaController {
dto.setExpirationDate(vacuna.getExpirationDate()); dto.setExpirationDate(vacuna.getExpirationDate());
dto.setPatientDocumentNumber(vacuna.getPatientDocumentNumber()); dto.setPatientDocumentNumber(vacuna.getPatientDocumentNumber());
dto.setReactions(vacuna.getReactions()); dto.setReactions(vacuna.getReactions());
dto.setPractitioner(receta.getPractitioner());
dto.setPractitionerDocumentNumber(receta.getPractitionerDocumentNumber());
return dto; return dto;
} }

View file

@ -28,4 +28,7 @@ public class Receta {
private String cantidad; private String cantidad;
//@JsonFormat(pattern = "yyyy-MM-dd") //@JsonFormat(pattern = "yyyy-MM-dd")
private String expectedSupplyDuration; private String expectedSupplyDuration;
private String practitioner;
private String practitionerDocumentNumber;
private String signature;
} }

View file

@ -27,4 +27,7 @@ public class RecetaDto {
private String cantidad; private String cantidad;
// @JsonFormat(pattern = "yyyy-MM-dd") // @JsonFormat(pattern = "yyyy-MM-dd")
private String expectedSupplyDuration; private String expectedSupplyDuration;
private String practitioner;
private String practitionerDocumentNumber;
private String signature;
} }

View file

@ -20,5 +20,7 @@ public class Vacuna {
private String expirationDate; private String expirationDate;
private String patientDocumentNumber; private String patientDocumentNumber;
private String reactions; private String reactions;
private String practitioner;
private String practitionerDocumentNumber;
} }

View file

@ -20,4 +20,6 @@ public class VacunaDto {
private String expirationDate; private String expirationDate;
private String patientDocumentNumber; private String patientDocumentNumber;
private String reactions; private String reactions;
private String practitioner;
private String practitionerDocumentNumber;
} }

View file

@ -149,6 +149,11 @@ public class RecetaService {
contract.submitTransaction("EntregarReceta", recetaId); contract.submitTransaction("EntregarReceta", recetaId);
} }
public void firmarReceta(String recetaId, String signature)
throws CommitStatusException, EndorseException, CommitException, SubmitException {
contract.submitTransaction("FirmarReceta", recetaId, signature);
}
public List<Receta> obtenerRecetasPorDniYEstado(String dni, String estado) throws GatewayException, IOException { public List<Receta> obtenerRecetasPorDniYEstado(String dni, String estado) throws GatewayException, IOException {
if (dni == null || dni.isBlank() || estado == null || estado.isBlank()) { if (dni == null || dni.isBlank() || estado == null || estado.isBlank()) {
throw new IllegalArgumentException("DNI y estado son obligatorios"); throw new IllegalArgumentException("DNI y estado son obligatorios");