mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
383 lines
11 KiB
Go
383 lines
11 KiB
Go
package chaincode
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/hyperledger/fabric-contract-api-go/v2/contractapi"
|
|
)
|
|
|
|
type SmartContract struct {
|
|
contractapi.Contract
|
|
}
|
|
|
|
type Receta struct {
|
|
ID string `json:"id"`
|
|
Identificador string `json:"identificador"`
|
|
Owner string `json:"owner"`
|
|
PrescripcionAnteriorId string `json:"prescripcionAnteriorId"`
|
|
Status string `json:"status"`
|
|
StatusChange string `json:"statusChange"`
|
|
Prioridad string `json:"prioridad"`
|
|
Medicacion string `json:"medicacion"`
|
|
Razon string `json:"razon"`
|
|
Notas string `json:"notas"`
|
|
PeriodoDeTratamiento string `json:"periodoDeTratamiento"`
|
|
InstruccionesTratamiento string `json:"instruccionesTratamiento"`
|
|
PeriodoDeValidez string `json:"periodoDeValidez"`
|
|
DniPaciente string `json:"dniPaciente"`
|
|
FechaDeAutorizacion string `json:"fechaDeAutorizacion"`
|
|
Cantidad string `json:"cantidad"`
|
|
ExpectedSupplyDuration string `json:"expectedSupplyDuration"`
|
|
}
|
|
|
|
type Vacuna struct {
|
|
ID string `json:"id"` // identificador único para el ledger
|
|
Identificador string `json:"identificador"`
|
|
Status string `json:"status"` // podés validarlo con enums si querés
|
|
StatusChange string `json:"statusChange"` // como string (ISO8601)
|
|
StatusReason string `json:"statusReason"`
|
|
VaccinateCode string `json:"vaccinateCode"`
|
|
AdministradedProduct string `json:"administradedProduct"`
|
|
Manufacturer string `json:"manufacturer"`
|
|
LotNumber string `json:"lotNumber"`
|
|
ExpirationDate string `json:"expirationDate"` // como string ISO8601
|
|
DniPaciente string `json:"dniPaciente"`
|
|
Reactions string `json:"reactions"` // puede ser un string o una estructura si querés después
|
|
}
|
|
|
|
|
|
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
|
|
recetas := []Receta{
|
|
{
|
|
ID: "receta1",
|
|
Identificador "rece1234"
|
|
Owner: "Tomoko",
|
|
PrescripcionAnteriorId: "presc123",
|
|
Status: "active",
|
|
StatusChange: "2024-01-15T10:00:00Z",
|
|
Prioridad: "high",
|
|
Medicacion: "medicacion1",
|
|
Razon: "razon1",
|
|
Notas: "algunas notas",
|
|
PeriodoDeTratamiento: "30 dias",
|
|
InstruccionesTratamiento: "una por dia",
|
|
PeriodoDeValidez: "1 anio",
|
|
DniPaciente: "12345678",
|
|
FechaDeAutorizacion: "2024-01-01T09:00:00Z",
|
|
Cantidad: "5",
|
|
ExpectedSupplyDuration: "2024-02-01T09:00:00Z",
|
|
},
|
|
{
|
|
ID: "receta2",
|
|
Identificador "rece1235"
|
|
Owner: "Alice",
|
|
PrescripcionAnteriorId: "presc456",
|
|
Status: "completed",
|
|
StatusChange: "2024-02-20T11:00:00Z",
|
|
Prioridad: "medium",
|
|
Medicacion: "medicacion2",
|
|
Razon: "razon2",
|
|
Notas: "otras notas",
|
|
PeriodoDeTratamiento: "60 dias",
|
|
InstruccionesTratamiento: "dos por dia",
|
|
PeriodoDeValidez: "2 anios",
|
|
DniPaciente: "87654321",
|
|
FechaDeAutorizacion: "2024-01-10T10:00:00Z",
|
|
Cantidad: "10",
|
|
ExpectedSupplyDuration: "2024-04-10T10:00:00Z",
|
|
},
|
|
}
|
|
|
|
for _, receta := range recetas {
|
|
recetaJSON, err := json.Marshal(receta)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = ctx.GetStub().PutState(receta.ID, recetaJSON)
|
|
if err != nil {
|
|
return fmt.Errorf("error al guardar receta en el ledger: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *SmartContract) CreateReceta(ctx contractapi.TransactionContextInterface, receta Receta) error {
|
|
exists, err := s.RecetaExists(ctx, receta.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
return fmt.Errorf("la receta %s ya existe", receta.ID)
|
|
}
|
|
|
|
recetaJSON, err := json.Marshal(receta)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ctx.GetStub().PutState(receta.ID, recetaJSON)
|
|
}
|
|
|
|
func (s *SmartContract) EntregarReceta(ctx contractapi.TransactionContextInterface, recetaID string) error {
|
|
exists, err := s.RecetaExists(ctx, recetaID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
return fmt.Errorf("la receta %s no existe", recetaID)
|
|
}
|
|
|
|
// Obtener la receta actual
|
|
recetaActualJSON, err := ctx.GetStub().GetState(recetaID)
|
|
if err != nil {
|
|
return fmt.Errorf("error al obtener la receta actual: %v", err)
|
|
}
|
|
if recetaActualJSON == nil {
|
|
return fmt.Errorf("la receta %s no fue encontrada en el ledger", recetaID)
|
|
}
|
|
|
|
var recetaActual Receta
|
|
if err := json.Unmarshal(recetaActualJSON, &recetaActual); err != nil {
|
|
return fmt.Errorf("error al parsear la receta actual: %v", err)
|
|
}
|
|
|
|
// Validar que el estado actual sea ACTIVO
|
|
if recetaActual.Status != "ACTIVO" {
|
|
return fmt.Errorf("solo se puede entregar la receta si está en estado 'ACTIVO'")
|
|
}
|
|
|
|
// Cambiar el estado a ENTREGADO
|
|
recetaActual.Status = "ENTREGADO"
|
|
|
|
// Guardar la receta modificada
|
|
updatedRecetaJSON, err := json.Marshal(recetaActual)
|
|
if err != nil {
|
|
return fmt.Errorf("error al serializar la receta modificada: %v", err)
|
|
}
|
|
|
|
return ctx.GetStub().PutState(recetaID, updatedRecetaJSON)
|
|
}
|
|
|
|
func (s *SmartContract) ReadReceta(ctx contractapi.TransactionContextInterface, id string) (*Receta, error) {
|
|
recetaJSON, err := ctx.GetStub().GetState(id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error al leer del ledger: %v", err)
|
|
}
|
|
if recetaJSON == nil {
|
|
return nil, fmt.Errorf("la receta %s no existe", id)
|
|
}
|
|
|
|
var receta Receta
|
|
err = json.Unmarshal(recetaJSON, &receta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &receta, nil
|
|
}
|
|
|
|
func (s *SmartContract) DeleteReceta(ctx contractapi.TransactionContextInterface, id string) error {
|
|
exists, err := s.RecetaExists(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
return fmt.Errorf("la receta %s no existe", id)
|
|
}
|
|
|
|
return ctx.GetStub().DelState(id)
|
|
}
|
|
|
|
func (s *SmartContract) RecetaExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
|
|
recetaJSON, err := ctx.GetStub().GetState(id)
|
|
if err != nil {
|
|
return false, fmt.Errorf("error al acceder al ledger: %v", err)
|
|
}
|
|
return recetaJSON != nil, nil
|
|
}
|
|
|
|
func (s *SmartContract) TransferirReceta(ctx contractapi.TransactionContextInterface, id string, nuevoOwner string) (string, error) {
|
|
receta, err := s.ReadReceta(ctx, id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
oldOwner := receta.Owner
|
|
receta.Owner = nuevoOwner
|
|
|
|
recetaJSON, err := json.Marshal(receta)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = ctx.GetStub().PutState(id, recetaJSON)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return oldOwner, nil
|
|
}
|
|
|
|
func (s *SmartContract) GetAllRecetas(ctx contractapi.TransactionContextInterface) ([]*Receta, error) {
|
|
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resultsIterator.Close()
|
|
|
|
var recetas []*Receta
|
|
for resultsIterator.HasNext() {
|
|
queryResponse, err := resultsIterator.Next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var receta Receta
|
|
err = json.Unmarshal(queryResponse.Value, &receta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
recetas = append(recetas, &receta)
|
|
}
|
|
|
|
return recetas, nil
|
|
}
|
|
|
|
func (s *SmartContract) GetMultipleRecetas(ctx contractapi.TransactionContextInterface, recetaIDs []string) ([]*Receta, error) {
|
|
var recetas []*Receta
|
|
for _, id := range recetaIDs {
|
|
recetaJSON, err := ctx.GetStub().GetState(id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error al leer del ledger: %v", err)
|
|
}
|
|
if recetaJSON == nil {
|
|
continue
|
|
}
|
|
|
|
var receta Receta
|
|
err = json.Unmarshal(recetaJSON, &receta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
recetas = append(recetas, &receta)
|
|
}
|
|
return recetas, nil
|
|
}
|
|
// 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) {
|
|
if dni == "" || estado == "" {
|
|
return nil, fmt.Errorf("el dni y el estado son obligatorios")
|
|
}
|
|
|
|
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error al obtener datos del ledger: %v", err)
|
|
}
|
|
defer resultsIterator.Close()
|
|
|
|
var recetasFiltradas []*Receta
|
|
for resultsIterator.HasNext() {
|
|
queryResponse, err := resultsIterator.Next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var receta Receta
|
|
err = json.Unmarshal(queryResponse.Value, &receta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if receta.DniPaciente == dni && receta.Status == estado {
|
|
recetasFiltradas = append(recetasFiltradas, &receta)
|
|
}
|
|
}
|
|
|
|
return recetasFiltradas, nil
|
|
}
|
|
|
|
func (s *SmartContract) CreateVacuna(ctx contractapi.TransactionContextInterface, vacuna Vacuna) error {
|
|
exists, err := s.VacunaExists(ctx, vacuna.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
return fmt.Errorf("la vacuna %s ya existe", vacuna.ID)
|
|
}
|
|
|
|
vacunaJSON, err := json.Marshal(vacuna)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ctx.GetStub().PutState(vacuna.ID, vacunaJSON)
|
|
}
|
|
|
|
func (s *SmartContract) VacunaExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
|
|
vacunaJSON, err := ctx.GetStub().GetState(id)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return vacunaJSON != nil, nil
|
|
}
|
|
|
|
unc (s *SmartContract) ReadVacuna(ctx contractapi.TransactionContextInterface, id string) (*Vacuna, error) {
|
|
vacunaJSON, err := ctx.GetStub().GetState(id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error al leer del ledger: %v", err)
|
|
}
|
|
if vacunaJSON == nil {
|
|
return nil, fmt.Errorf("la vacuna %s no existe", id)
|
|
}
|
|
|
|
var vacuna Vacuna
|
|
err = json.Unmarshal(vacunaJSON, &vacuna)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &vacuna, nil
|
|
}
|
|
|
|
func (s *SmartContract) GetVacunasPorDniYEstado(ctx contractapi.TransactionContextInterface, dni string, estado string) ([]*Vacuna, error) {
|
|
if dni == "" {
|
|
return nil, fmt.Errorf("el dni es obligatorio")
|
|
}
|
|
|
|
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error al obtener datos del ledger: %v", err)
|
|
}
|
|
defer resultsIterator.Close()
|
|
|
|
var vacunasFiltradas []*Vacuna
|
|
for resultsIterator.HasNext() {
|
|
queryResponse, err := resultsIterator.Next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var vacuna Vacuna
|
|
// Solo deserializamos si es posible (podría fallar si no es una vacuna)
|
|
if err := json.Unmarshal(queryResponse.Value, &vacuna); err != nil {
|
|
continue
|
|
}
|
|
|
|
// Validamos que tenga un DNI y coincida
|
|
if vacuna.DniPaciente != dni {
|
|
continue
|
|
}
|
|
|
|
// Si se pasó un estado, lo filtramos
|
|
if estado != "" && vacuna.Status != estado {
|
|
continue
|
|
}
|
|
|
|
vacunasFiltradas = append(vacunasFiltradas, &vacuna)
|
|
}
|
|
|
|
return vacunasFiltradas, nil
|
|
}
|