pragma solidity ^0.4.22; /* Invoice contract Represents a single sales invoice issued from a vendor to a customer © 2019 RTA Written by Tom Hall, January 2019 */ contract invoice { // Contract variables address public callers; // Users who are, or have been, authorised to access protected contract functions address public vendor; // Address of vendor address public customer; // Address of customer string public singleEntry; // Single Entry accounting baby string public decryptionKey; // Key to decrypt IPFS hashes bool public matched; // Match status of invoice bool public auditOpinions; // Audit opinions // Access rights object struct accessRights { string role; // Access rights' user role bool valid; // Validity of access rights bool grantedByVendor; // Source of access rights } // Audit opinion object struct auditOpinion { address auditor; // Auditor address string detailedOpinion; // Auditor opinion detail } // Event logging (ledger) event submissionEvent( bool vendor, // Submitting party uint rtaPoint, // RTA timestamp string encryptedIpfsHash, // IPFS hash of encrypted submission data bool status // Match status on submission ); // Invoice callers mapping => access rights mapping (address => accessRights) access; // Access control // Audit opinion mapping => mapping (bool => auditOpinion) opinion; // Opinion mapping // MATCHING FUNCTIONS /** @dev Constructor function * @param _encryptedIpfsHash Encrypted IPFS hash * @param _customer Customer Address * @param _decryptionKey Decryption Key for IPFS Hash */ function invoice(string _encryptedIpfsHash, address _customer, string _decryptionKey) public { // Set contract variables - permanent vendor = msg.sender; // Set vendor customer = _customer; // Set customer decryptionKey = _decryptionKey; // Set protected decryptionKey // Set contract variables - temporary singleEntry = _encryptedIpfsHash; // Set current vendorRecords matched = false; // Set match status // Save data to logs emit submissionEvent(true, now, _encryptedIpfsHash, false); } /** @dev Updates invoice values. Restricted to vendor and customer only * @param _encryptedIpfsHash User Submission */ function updateInvoice(string _encryptedIpfsHash) public isParty(msg.sender) { testMatch(_encryptedIpfsHash); if (msg.sender == vendor) { emit submissionEvent(matched, now, _encryptedIpfsHash, true); } else { emit submissionEvent(matched, now, _encryptedIpfsHash, false); } singleEntry = _encryptedIpfsHash; // Set latest encrypted IPFS Hash } /** @dev Matching function * @param _encryptedIpfsHash Value to test */ function testMatch(string _encryptedIpfsHash) private isParty(msg.sender) { if (_encryptedIpfsHash == singleEntry) { matched = true; } else { matched = false; } } function getInvoice() public returns (string) { return singleEntry; } // FACTORING FUNCTIONS function sellInvoice(address _newOwner) public isVendor(msg.sender) { /* . Calls _newOwner receiver to create new invoice contract New IPFS hash generated replacing vendor data with _newOwner data ... we want the customer to retain the same contract address... ??? */ } function collateraliseInvoice(address _creditor) isVendor(msg.sender) public { } // AUDITING FUNCTIONS function provideAuditOpinion(bool _auditOpinion, string _detailedOpinion) public { auditOpinions(_auditOpinion).opinion.auditor = msg.sender; auditOpinions(_auditOpinion).opinion.detailedOpinion = _detailedOpinion; } // ACCESS CONTROLS /** @dev Returns key needed to decrypt IPFS hash of encrypted data * @return decryptionkey Decryption key */ // TO DO: decryption key access logging function getDecryptionKey() canAccess(msg.sender) public returns (string) { return decryptionKey; } /** @dev Grants access rights and sets role of specified user * @param _party Specified user address * @param _role Specified user access role */ // TO DO: access control logging function grantAccess(address _caller, string _role) partyCanShareWith(_caller) { callers(_caller).access.valid = true; callers(_caller).access.role = _role; if (msg.sender == vendor) { callers(_caller).access.grantedByVendor = true; } else { callers(_caller).access.grantedByVendor = false; } } /** @dev Revokes access rights of specified user * @param _party Specified user address */ // TO DO: access control logging function revokeAccessFor(address _caller) partyCanShareWith(_caller) { callers(_caller).access.valid = false; } /** @dev Determines if user can update access rights of specified user * @param _party Specified user address */ modifier partyCanShareWith(address _caller) { // If not vendor or customer then exit if (msg.sender != vendor || customer) { throw; } // Vendor controls shares with vendor's callers only if (msg.sender == vendor && callers(_caller).access.grantedByVendor == false) { throw; } // Customer controls shares with customer's callers only if (msg.sender == customer && callers(_caller).access.grantedByVendor == true) { throw; } } /** @dev Determines if caller is party to the invoice */ modifier isParty() { require(msg.sender == (vendor || customer)); } modifier isVendor() { require(msg.sender == vendor); } /** @dev Determines if caller can access function */ modifier canAccess() { require(msg.sender == (vendor || customer) || (callers(msg.sender).access.valid == true)); } }
0.4.22