From 21455bfd1004c4a3153050ac5995b8dc680c2042 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Wed, 27 Jul 2016 16:48:53 +0200 Subject: Class names start with a capital --- classes/Assignment.php | 287 +++++++++++++++++ classes/BusinessAdmin.php | 42 +-- classes/Client.php | 108 +++++++ classes/Constants.php | 84 +++++ classes/Contact.php | 384 +++++++++++++++++++++++ classes/Correspondence.php | 317 +++++++++++++++++++ classes/Discount.php | 256 ++++++++++++++++ classes/FPDF.license.txt | 6 + classes/File.php | 148 +++++++++ classes/Model.php | 2 +- classes/Offer.php | 747 +++++++++++++++++++++++++++++++++++++++++++++ classes/Payment.php | 142 +++++++++ classes/Response.php | 112 +++++++ classes/User.php | 198 ++++++++++++ classes/assignment.php | 287 ----------------- classes/client.php | 108 ------- classes/constants.php | 84 ----- classes/contact.php | 384 ----------------------- classes/correspondence.php | 317 ------------------- classes/discount.php | 256 ---------------- classes/file.php | 148 --------- classes/fpdf.license.txt | 6 - classes/offer.php | 747 --------------------------------------------- classes/payment.php | 142 --------- classes/response.php | 112 ------- classes/user.php | 198 ------------ 26 files changed, 2811 insertions(+), 2811 deletions(-) create mode 100644 classes/Assignment.php create mode 100644 classes/Client.php create mode 100644 classes/Constants.php create mode 100644 classes/Contact.php create mode 100644 classes/Correspondence.php create mode 100644 classes/Discount.php create mode 100644 classes/FPDF.license.txt create mode 100644 classes/File.php create mode 100644 classes/Offer.php create mode 100644 classes/Payment.php create mode 100644 classes/Response.php create mode 100644 classes/User.php delete mode 100644 classes/assignment.php delete mode 100644 classes/client.php delete mode 100644 classes/constants.php delete mode 100644 classes/contact.php delete mode 100644 classes/correspondence.php delete mode 100644 classes/discount.php delete mode 100644 classes/file.php delete mode 100644 classes/fpdf.license.txt delete mode 100644 classes/offer.php delete mode 100644 classes/payment.php delete mode 100644 classes/response.php delete mode 100644 classes/user.php (limited to 'classes') diff --git a/classes/Assignment.php b/classes/Assignment.php new file mode 100644 index 0000000..b4a67dc --- /dev/null +++ b/classes/Assignment.php @@ -0,0 +1,287 @@ +. + */ + +/** + * An interface to the assignment table in the database + */ +class Assignment { + use Calculatable; + + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the assignment + * @var int $offerId The id of the offer this assignment is linked to + * @var string $title The title of the assignment + * @var string $description The description of the assignment + * @var int $hours The amount of hours of the assignment + * @var float $price_per_hour The price per hour for this assignment, in your valuta + * @var float $vat The percentage of VAT to calculate on this assignment + */ + protected $pdo, $offerId, $id, $title, $description, $hours, $price_per_hour, $vat; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the assignment to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the assignment could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."assignment` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The assignment with id '$id' could not be found."); + } + $assignment = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $assignment['id']; + $this->offerId = $assignment['offerId']; + $this->title = $assignment['title']; + $this->description = $assignment['description']; + $this->hours = $assignment['hours']; + $this->price_per_hour = $assignment['price_per_hour']; + $this->vat = $assignment['VAT_percentage']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the assignment + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the offer that this assignment is linked to + * + * @return int The ID + */ + public function getOfferId() { + return $this->offerId; + } + + /** + * Get the offer that this assignment is linked to + * + * @return offer The offer + */ + public function getOffer() { + return new Offer($this->pdo, $this->offerId); + } + + /** + * Get the title of the assignment + * + * @return string The title + */ + public function getTitle() { + return $this->title; + } + + /** + * Set the title of the assignment + * + * @param string $title The new title for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setTitle($title) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."assignment` SET `title`=? WHERE `id`=?"); + $stmt->execute(array($title, $this->id)); + if ($stmt->rowCount() == 1) { + $this->title = $title; + return true; + } else { + return false; + } + } + + /** + * Get the description of the assignment + * + * @param bool $parseMarkdown Whether or not to parse markdown + * + * @return string The description + */ + public function getDescription($parseMarkdown = true) { + if ($parseMarkdown) { + $pd = new Parsedown; + return $pd->text($this->description); + } else { + return $this->description; + } + } + + /** + * Set the description of the assignment + * + * @param string $description The new description for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setDescription($description) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."assignment` SET `description`=? WHERE `id`=?"); + $stmt->execute(array($description, $this->id)); + if ($stmt->rowCount() == 1) { + $this->description = $description; + return true; + } else { + return false; + } + } + + /** + * Get the amount of hours of the assignment + * + * @return int The amount of hours + */ + public function getHours() { + return $this->hours; + } + + /** + * Set the amount of hours of the assignment + * + * @param int $hours The new amount hours for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setHours($hours) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."assignment` SET `hours`=? WHERE `id`=?"); + $stmt->execute(array($hours, $this->id)); + if ($stmt->rowCount() == 1) { + $this->hours = $hours; + return true; + } else { + return false; + } + } + + /** + * Get the price per hour of the assignment + * + * @return float The price per hour + */ + public function getPricePerHour() { + return $this->price_per_hour; + } + + /** + * Set the price per hour of the assignment + * + * @param float $price_per_hour The new price per hour for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPricePerHour($price_per_hour) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."assignment` SET `price_per_hour`=? WHERE `id`=?"); + $stmt->execute(array($price_per_hour, $this->id)); + if ($stmt->rowCount() == 1) { + $this->price_per_hour = $price_per_hour; + return true; + } else { + return false; + } + } + + /** + * Get the VAT percentage of the assignment + * + * @return float The VAT percentage + */ + public function getVAT() { + return $this->vat; + } + + /** + * Set the VAT percentage of the assignment + * + * @param float $vat The new VAT percentage for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setVAT($vat) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."assignment` SET `VAT_percentage`=? WHERE `id`=?"); + $stmt->execute(array($vat, $this->id)); + if ($stmt->rowCount() == 1) { + $this->vat = $vat; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + protected function calculateSubtotal() { + return $this->getHours() * $this->getPricePerHour(); + } + + protected function calculateVAT() { + return $this->calculateSubtotal() * $this->getVAT() / 100; + } + + /** + * Remove this assignment from the database + * + * If this doesn't succeed (i.e. false is returned), that means the assignment was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."assignment` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} diff --git a/classes/BusinessAdmin.php b/classes/BusinessAdmin.php index 347c9c6..3e654a2 100644 --- a/classes/BusinessAdmin.php +++ b/classes/BusinessAdmin.php @@ -44,7 +44,7 @@ class BusinessAdmin { */ public static function getUserIds($pdo, $where = [], $variables = []) { $ids = []; - $users = $pdo->prepare("SELECT `id` FROM `".constants::db_prefix."user`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : "")); + $users = $pdo->prepare("SELECT `id` FROM `".Constants::db_prefix."user`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : "")); $users->execute($variables); $users = $users->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $user) { @@ -70,7 +70,7 @@ class BusinessAdmin { $ids = self::getUserIds($pdo, $where, $variables); $users = []; foreach ($ids as $id) { - $users[$id] = new user($pdo, $id); + $users[$id] = new User($pdo, $id); } return $users; } @@ -88,7 +88,7 @@ class BusinessAdmin { */ public static function getClientIds($pdo) { $ids = array(); - $clients = $pdo->query("SELECT `id` FROM `".constants::db_prefix."client`")->fetchAll(PDO::FETCH_ASSOC); + $clients = $pdo->query("SELECT `id` FROM `".Constants::db_prefix."client`")->fetchAll(PDO::FETCH_ASSOC); foreach ($clients as $client) { $ids[] = $client['id']; } @@ -110,7 +110,7 @@ class BusinessAdmin { $ids = self::getClientIds($pdo); $clients = array(); foreach ($ids as $id) { - $clients[$id] = new client($pdo, $id); + $clients[$id] = new Client($pdo, $id); } return $clients; } @@ -128,7 +128,7 @@ class BusinessAdmin { */ public static function getContactIds($pdo) { $ids = array(); - $contacts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."contact`")->fetchAll(PDO::FETCH_ASSOC); + $contacts = $pdo->query("SELECT `id` FROM `".Constants::db_prefix."contact`")->fetchAll(PDO::FETCH_ASSOC); foreach ($contacts as $contact) { $ids[] = $contact['id']; } @@ -150,7 +150,7 @@ class BusinessAdmin { $ids = self::getContactIds($pdo); $contacts = array(); foreach ($ids as $id) { - $contacts[$id] = new contact($pdo, $id); + $contacts[$id] = new Contact($pdo, $id); } return $contacts; } @@ -169,7 +169,7 @@ class BusinessAdmin { */ public static function getOfferIds($pdo, $where = array()) { $ids = array(); - $offers = $pdo->query("SELECT `id` FROM `".constants::db_prefix."offer`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + $offers = $pdo->query("SELECT `id` FROM `".Constants::db_prefix."offer`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); foreach ($offers as $offer) { $ids[] = $offer['id']; } @@ -192,7 +192,7 @@ class BusinessAdmin { $ids = self::getOfferIds($pdo, $where); $offers = array(); foreach ($ids as $id) { - $offers[$id] = new offer($pdo, $id); + $offers[$id] = new Offer($pdo, $id); } return $offers; } @@ -211,7 +211,7 @@ class BusinessAdmin { */ public static function getAssignmentIds($pdo, $where = array()) { $ids = array(); - $assignments = $pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + $assignments = $pdo->query("SELECT `id` FROM `".Constants::db_prefix."assignment`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); foreach ($assignments as $assignment) { $ids[] = $assignment['id']; } @@ -234,7 +234,7 @@ class BusinessAdmin { $ids = self::getAssignmentIds($pdo, $where); $assignments = array(); foreach ($ids as $id) { - $assignments[$id] = new assignment($pdo, $id); + $assignments[$id] = new Assignment($pdo, $id); } return $assignments; } @@ -253,7 +253,7 @@ class BusinessAdmin { */ public static function getDiscountIds($pdo, $where = array()) { $ids = array(); - $discounts = $pdo->query("SELECT `id` FROM `".constants::db_prefix."discount`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); + $discounts = $pdo->query("SELECT `id` FROM `".Constants::db_prefix."discount`" . ((count($where) > 0) ? (" WHERE (" . implode(') AND (', $where) . ")") : ""))->fetchAll(PDO::FETCH_ASSOC); foreach ($discounts as $discount) { $ids[] = $discount['id']; } @@ -276,7 +276,7 @@ class BusinessAdmin { $ids = self::getDiscountIds($pdo, $where); $discounts = array(); foreach ($ids as $id) { - $discounts[$id] = new discount($pdo, $id); + $discounts[$id] = new Discount($pdo, $id); } return $discounts; } @@ -296,10 +296,10 @@ class BusinessAdmin { * @return client|bool A new instance of the client object, or false on failure */ public static function createClient($pdo, $name) { - $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."client` (`name`) VALUES (?)"); + $stmt = $pdo->prepare("INSERT INTO `".Constants::db_prefix."client` (`name`) VALUES (?)"); $stmt->execute(array($name)); if ($stmt->rowCount() == 1) { - return new client($pdo, $pdo->lastInsertId()); + return new Client($pdo, $pdo->lastInsertId()); } else { return false; } @@ -318,21 +318,21 @@ class BusinessAdmin { */ public static function createFile($pdo, $filename) { // Check for file existence - if (file_exists(constants::files_folder . $filename)) { + if (file_exists(Constants::files_folder . $filename)) { throw new Exception("$filename already exists."); } // Try to create the file - if (file_put_contents(constants::files_folder . $filename, '') === false) { + if (file_put_contents(Constants::files_folder . $filename, '') === false) { throw new Exception("$filename could not be created. Check the permissions."); } - $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."file` (`filename`) VALUES (?)"); + $stmt = $pdo->prepare("INSERT INTO `".Constants::db_prefix."file` (`filename`) VALUES (?)"); $stmt->execute(array($filename)); if ($stmt->rowCount() == 1) { - return new file($pdo, $pdo->lastInsertId()); + return new File($pdo, $pdo->lastInsertId()); } else { - unlink(constants::files_folder . $filename); + unlink(Constants::files_folder . $filename); throw new Exception("$filename could not be added to the database"); } } @@ -349,10 +349,10 @@ class BusinessAdmin { * @return user|bool A new instance of the user object, or false on failure */ public static function createUser($pdo, $username, $password) { - $stmt = $pdo->prepare("INSERT INTO `".constants::db_prefix."user` (`username`, `password`) VALUES (?,?)"); + $stmt = $pdo->prepare("INSERT INTO `".Constants::db_prefix."user` (`username`, `password`) VALUES (?,?)"); $stmt->execute([$username, user::hash($password)]); if ($stmt->rowCount() == 1) { - return new user($pdo, $pdo->lastInsertId()); + return new User($pdo, $pdo->lastInsertId()); } else { return false; } diff --git a/classes/Client.php b/classes/Client.php new file mode 100644 index 0000000..13e28d7 --- /dev/null +++ b/classes/Client.php @@ -0,0 +1,108 @@ +. + */ + +/** + * An interface to the client table in the database + */ +class Client extends Model { + public + $table = 'client', + $fillable_columns = ['name']; + + /** + * Get all contact ids for this client + * + * @see client::getContacts() This funtion returns instances of the contact class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getContactIds() { + $ids = array(); + $contacts = $this->pdo->query("SELECT `id` FROM `".Constants::db_prefix."contact` WHERE `clientId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($contacts as $contact) { + $ids[] = $contact['id']; + } + return $ids; + } + + /** + * Get all contacts for this client + * + * @see client::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class + * + * @throws PDOException If something went wrong with the database + * + * @return contact[] An array indexed by id of instances of the contact class + */ + public function getContacts() { + $ids = $this->getContactIds(); + $contacts = array(); + foreach ($ids as $id) { + $contacts[$id] = new Contact($this->pdo, $id); + } + return $contacts; + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Make a new contact for this client + * + * @param string $name The name for this contact + * @param string $email The email for this contact + * @param string $address The first address line of this contact (normally street and house number) + * @param string $address_2 The second address line of this contact + * @param string $postal_code The postal code for this contact + * @param string $city The city for this contact + * @param string $state The state for this contact + * @param string $country The country for this contact + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return contact A new instance of the contact class containing the new contact + */ + public function createContact($name, $email, $address, $address_2, $postal_code, $city, $country) { + $stmt = $this->pdo->prepare("INSERT INTO `".Constants::db_prefix."contact` (`clientId`,`name`,`email`,`address`,`address_2`,`postal_code`,`city`,`country`) VALUES (?,?,?,?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $name, + $email, + $address, + $address_2, + $postal_code, + $city, + $country + )); + if ($stmt->rowCount() == 1) { + return new Contact($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } +} diff --git a/classes/Constants.php b/classes/Constants.php new file mode 100644 index 0000000..3ffadd7 --- /dev/null +++ b/classes/Constants.php @@ -0,0 +1,84 @@ +. + */ + +/** + * A class for some constants + */ +class Constants { + /** @const db_prefix A prefix to add to the tables in the database (leave empty for none) */ + const db_prefix = ''; + + /** @const files_folder The folder to store all files (appendices, invoices, etc.) in; with a trailing slash */ + const files_folder = '/var/www/localhost/BusinessAdmin/files/'; + /** @const files_folder_external The external URI to this folder; with a trailing slash */ + const files_folder_external = 'http://localhost/BusinessAdmin/files/'; + /** @const files_folder_trash The folder inside files_folder to use a trash, without any trailing slashes */ + const files_folder_trash = 'trash'; + + /** @const url_external The external URI to this folder; with a trailing slash */ + const url_external = 'http://localhost/BusinessAdmin/'; + /** @const url_internal The URI without the domain name; with a slash at the beginning but not at the end */ + const url_internal = '/BusinessAdmin'; + + /** @const my_name Name of this control panel */ + const my_name = 'BusinessAdmin'; + + /** + * @const invoice_name Your name or the name of your business + * @const invoice_address_1 First address line + * @const invoice_address_2 Second address line + * @const invoice_address_3 Third address line + * @const invoice_tax_nr Your tax number + * @const invoice_iban Your IBAN number + * @const invoice_bic The BIC code of your bank + * @const invoice_tel_nr Your telephone number + * @const invoice_email Your email address + * @const invoice_valuta The valuta symbol (will be placed in front of amounts). You can use a symbol like $ or a code like USD + */ + const invoice_name = 'BusinessAdmin'; + const invoice_address_1 = 'My Street 1'; + const invoice_address_2 = '12345 My City'; + const invoice_address_3 = 'My Country'; + const invoice_tax_nr = 'XX123456789A00'; + const invoice_iban = 'XX00 ABCD 1234 5678 90'; + const invoice_bic = 'XXXX XXXX'; + const invoice_tel_nr = '+31 6 1234 5678'; + const invoice_email = 'my-email@domain.tld'; + const invoice_valuta = '€'; + + /** @const fa_valuta see http://fontawesome.io/icons/#currency; the fa- postfix for valuta */ + const fa_valuta = 'eur'; + + /** @const user_admins The user ids that have administrator rights (creating and deleting users) */ + const user_admins = [1]; + + /** + * @const password_algo Algorithm for the password_hash function. + * @const password_cost Cost for the password_hash function. Run install?password_cost to benchmark your system + */ + const password_algo = PASSWORD_DEFAULT; + const password_cost = 10; + + /** @const version Version of BusinessAdmin. Don't change this yourself! */ + const version = '0.4.2'; +} diff --git a/classes/Contact.php b/classes/Contact.php new file mode 100644 index 0000000..6ed2a78 --- /dev/null +++ b/classes/Contact.php @@ -0,0 +1,384 @@ +. + */ + +/** + * An interface to the contact table in the database + */ +class Contact { + /** + * @var PDO $pdo The PDO class for database communication + * @var int $id The id of the contact + * @var int $clientId The id of the client the contact is linked to + * @var string $name The name of the contact + * @var string $email The email address of the contact + * @var string $address The first address line (normally street and house number) of the contact + * @var string $address_2 The second address line (can be null) + * @var string $postal_code The postal code of the contact + * @var string $city The city of the contact + * @var string $country The country of the contact + * @var string $language The language of the contact + */ + protected $pdo, $id, $clientId, $name, $email, $address, $postal_code, $city, $country, $language; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the contact to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the contact could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."contact` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The contact with id '$id' could not be found."); + } + $contact = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $contact['id']; + $this->clientId = $contact['clientId']; + $this->name = $contact['name']; + $this->email = $contact['email']; + $this->address = $contact['address']; + $this->address_2 = $contact['address_2']; + $this->postal_code = $contact['postal_code']; + $this->city = $contact['city']; + $this->country = $contact['country']; + $this->language = $contact['language']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the contact + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the client that this contact is linked to + * + * @return int The ID + */ + public function getClientId() { + return $this->clientId; + } + + /** + * Get the client that this contact is linked to + * + * @return client The client + */ + public function getClient() { + return new Client($this->pdo, $this->clientId); + } + + /** + * Get the name of the contact + * + * @return string The name + */ + public function getName() { + return $this->name; + } + + /** + * Set the name of the contact + * + * @param string $name The new name for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setName($name) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `name`=? WHERE `id`=?"); + $stmt->execute(array($name, $this->id)); + if ($stmt->rowCount() == 1) { + $this->name = $name; + return true; + } else { + return false; + } + } + + /** + * Get the email of the contact + * + * @return string The email + */ + public function getEmail() { + return $this->email; + } + + /** + * Set the email of the contact + * + * @param string $email The new email for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setEmail($email) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `email`=? WHERE `id`=?"); + $stmt->execute(array($email, $this->id)); + if ($stmt->rowCount() == 1) { + $this->email = $email; + return true; + } else { + return false; + } + } + + /** + * Get the first address line of the contact + * + * @return string The address + */ + public function getAddress() { + return $this->address; + } + + /** + * Set the first address line of the contact + * + * @param string $address The new address for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setAddress($address) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `address`=? WHERE `id`=?"); + $stmt->execute(array($address, $this->id)); + if ($stmt->rowCount() == 1) { + $this->address = $address; + return true; + } else { + return false; + } + } + + /** + * Get the second address line of the contact + * + * @return string The address + */ + public function getAddress_2() { + return $this->address_2; + } + + /** + * Set the second address line of the contact + * + * @param string $address_2 The new address for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setAddress_2($address_2) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `address_2`=? WHERE `id`=?"); + $stmt->execute(array($address_2, $this->id)); + if ($stmt->rowCount() == 1) { + $this->address_2 = $address_2; + return true; + } else { + return false; + } + } + + /** + * Get the postal_code of the contact + * + * @return string The postal_code + */ + public function getPostalCode() { + return $this->postal_code; + } + + /** + * Set the postal code of the contact + * + * @param $postal_code string The new postal code for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPostalCode($postal_code) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `postal_code`=? WHERE `id`=?"); + $stmt->execute(array($postal_code, $this->id)); + if ($stmt->rowCount() == 1) { + return true; + $this->postal_code = $postal_code; + } else { + return false; + } + } + + /** + * Get the city of the contact + * + * @return string The city + */ + public function getCity() { + return $this->city; + } + + /** + * Set the city of the contact + * + * @param string $city The new city for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setCity($city) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `city`=? WHERE `id`=?"); + $stmt->execute(array($city, $this->id)); + if ($stmt->rowCount() == 1) { + $this->city = $city; + return true; + } else { + return false; + } + } + + /** + * Get the country of the contact + * + * @return string The country + */ + public function getCountry() { + return $this->country; + } + + /** + * Set the country of the contact + * + * @param string $country The new country for the contact + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setCountry($country) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `country`=? WHERE `id`=?"); + $stmt->execute(array($country, $this->id)); + if ($stmt->rowCount() == 1) { + $this->country = $country; + return true; + } else { + return false; + } + } + + /** + * Get the language of the contact + * + * @return string The language + */ + public function getLanguage() { + return $this->language; + } + + /** + * Set the language of the contact + * + * @see correspondence::LANGUAGES The available languages + * + * @param string $language The new language for the contact + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the language is unknown + * + * @return bool True on succes, false on failure + */ + public function setLanguage($language) { + if (!in_array($language, correspondence::LANGUAGES)) { + throw new Exception("Language $language not available."); + } + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."contact` SET `language`=? WHERE `id`=?"); + $stmt->execute(array($language, $this->id)); + if ($stmt->rowCount() == 1) { + $this->language = $language; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Remove this contact from the database + * + * If this doesn't succeed (i.e. false is returned), that means the contact was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."contact` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } + + /** + * Make a new offer for this contact + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return offer A new instance of the offer class containing the new offer + */ + public function createOffer() { + $stmt = $this->pdo->prepare("INSERT INTO `".Constants::db_prefix."offer` (`contactId`) VALUES (?)"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() == 1) { + return new Offer($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } +} diff --git a/classes/Correspondence.php b/classes/Correspondence.php new file mode 100644 index 0000000..4c7a23b --- /dev/null +++ b/classes/Correspondence.php @@ -0,0 +1,317 @@ +. + */ + +/** + * An extension of FPDF to generate personalized correspondence PDFs + */ +class Correspondence extends FPDF { + /** + * @var $contact Holds the contact this correspondence will be sent to + * @var $language Holds the language this correspondence should be sent in + */ + var $contact, $language; + + /** + * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs + */ + const HEAD_RED = 0; + const HEAD_GREEN = 0; + const HEAD_BLUE = 0; + + /** + * Available languages + * + * @see _() Translation function + * @see $translations Translations table + */ + const LANGUAGES = ['en', 'nl']; + + /** + * Array holding the translations + * + * @see _() A function to translate + */ + protected static $translations = array( + 'adres' => array( + 'en' => 'Address', + 'nl' => 'Adres'), + 'amount' => array( + 'en' => 'Amount', + 'nl' => 'Subtotaal'), + 'amount-due' => array( + 'en' => 'Total amount due', + 'nl' => 'Te voldoen'), + 'biccode' => array( + 'en' => 'The BIC code of our bank is %%.', + 'nl' => 'De BIC-code van de bank is %%.'), + 'btwnr' => array( + 'en' => 'VAT nr', + 'nl' => 'BTW nr'), + 'description' => array( + 'en' => 'Description', + 'nl' => 'Omschrijving'), + 'due-date' => array( + 'en' => 'Due date', + 'nl' => 'Vervaldatum'), + 'email' => array( + 'en' => 'Email', + 'nl' => 'Email'), + 'iban' => array( + 'en' => 'IBAN', + 'nl' => 'IBAN'), + 'invoice' => array( + 'en' => 'Invoice', + 'nl' => 'Factuur'), + 'invoice-date' => array( + 'en' => 'Invoice date', + 'nl' => 'Factuurdatum'), + 'invoice-nr' => array( + 'en' => 'Invoice number', + 'nl' => 'Factuurnummer'), + 'price-excl' => array( + 'en' => 'Price excl.', + 'nl' => 'Prijs excl.'), + 'price-incl' => array( + 'en' => 'Price incl.', + 'nl' => 'Prijs incl.'), + 'request' => array( + 'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.', + 'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'), + 'tel-nr' => array( + 'en' => 'Tel.', + 'nl' => 'Tel.'), + 'total' => array( + 'en' => 'Total', + 'nl' => 'Totaal'), + 'vat' => array( + 'en' => 'VAT', + 'nl' => 'BTW'), + ); + + /** @var $page_height The height of a page in millimeters */ + protected static $page_height = 297; // A4 + /** @var $margin_bottom The bottom margin in millimeters */ + protected static $margin_bottom = 30; + + /** + * Translate a string + * + * @see $translations The array holding the translations + * + * @param string $key The string to translate + * @param string $lang The language to translate to (two-letter code) + * + * @return string The translated string + */ + public function _($key) { + if (!array_key_exists($key, self::$translations)) + return $key; + return self::$translations[$key][$this->language]; + } + + /** + * Create a new PDF + * + * @param string $orientation See the FPDF class specs + * @param string $unit See the FPDF class specs + * @param string $size See the FPDF class specs + */ + function __construct() { + $this->FPDF('P','mm','A4'); + + $this->SetMargins(30,20,20); + $this->SetAuthor(Constants::invoice_name); + $this->SetCreator('BusinessAdmin Correspondence Generator'); + $this->SetDisplayMode('fullpage','continuous'); + } + + /** + * Workaround for euro signs + * + * Euro signs in FPDF should be chr(128). Other signs don't have to be changed. + * + * @return a valuta symbol that can be used in FPDF + */ + public static function valuta() { + switch (Constants::invoice_valuta) { + case '€': + return chr(128); + default: + return Constants::invoice_valuta; + } + } + + /** + * Set the language of the correspondence (used to translate stuff) + * + * @param string $lang The language, two letter code ('en', 'nl', ...) + */ + function SetLangauge($lang) { + $supported = array('nl', 'en'); + if (!in_array($lang, $supported)) { + throw new Exception("Language not supported"); + } else { + $this->language = $lang; + } + } + + /** + * Set the contact to whom this correspondence will be sent (used for the address) + * + * @param contact $contact The contact + */ + function SetContact($contact) { + $this->contact = $contact; + + $this->language = $contact->getLanguage(); + } + + /** + * Makes a header with your details and the address of the contact + */ + function CorrespondenceHeader() { + if (file_exists(Constants::files_folder . 'logo-correspondence.png')) { + $this->Image(Constants::files_folder . 'logo-correspondence.png',30,20,50); + } + + $this->SetFont('Helvetica','',7); + $this->Cell(110,20); + $this->Cell(12,1,' ','T'); + $this->Cell(2,1); + $this->Cell(35,1,' ','T'); + $this->Ln(); + + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5,$this->_('adres'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, Constants::invoice_name); + $this->Ln(); + + $this->Cell(124,3.5); + $this->Cell(35,3.5, Constants::invoice_address_1); + $this->Ln(); + $this->Cell(124,3.5); + $this->Cell(35,3.5, Constants::invoice_address_2); + $this->Ln(); + $this->Cell(124,3.5); + $this->Cell(35,3.5, Constants::invoice_address_3); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5,$this->_('btwnr'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, Constants::invoice_tax_nr); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('iban'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, Constants::invoice_iban); + $this->Ln(); + $this->Cell(160,1.5); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('','',7); + $this->Cell(35,3.5, Constants::invoice_tel_nr); + $this->Ln(); + $this->Cell(110,3.5); + $this->SetFont('','B'); + $this->Cell(12,3.5, $this->_('email'),'',0,'R'); + $this->Cell(2,3.5); + $this->SetFont('',''); + $this->Cell(35,3.5, Constants::invoice_email); + $this->Ln(); + $this->Cell(110,1); + $this->Cell(12,1,' ','B'); + $this->Cell(2,1); + $this->Cell(35,1,' ','B'); + $this->Ln(); + $this->Cell(160,15); + $this->Ln(); + + $this->SetFont('','',11); + $this->SetXY(30,56.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getName())); + $this->Ln(); + $this->SetXY(30,61.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getAddress())); + $this->Ln(); + $this->SetXY(30,66.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getPostalCode().' '.$this->contact->getCity())); + $this->Ln(); + $this->SetXY(30,71.5); + $this->Cell(90,5.5,utf8_decode($this->contact->getCountry())); + $this->Ln(); + } + + /** + * Put PDF information + */ + function _putinfo() + { + $this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator')); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); + } + + /** + * Have we reached the bottom of the page yet? + * + * @return bool + */ + public function endOfPage() { + return ($this->GetY() > self::$page_height - self::$margin_bottom); + } + + /** + * Start a new page if we're on the end + */ + public function addPageIfOnEnd() { + if ($this->endOfPage()) { + $this->Ln(); + $this->AddPage(); + $this->Cell(100, 5, ''); // blank line + $this->Ln(); + } + } +} diff --git a/classes/Discount.php b/classes/Discount.php new file mode 100644 index 0000000..91dd53b --- /dev/null +++ b/classes/Discount.php @@ -0,0 +1,256 @@ +. + */ + +/** + * An interface to the discount table in the database + */ +class Discount { + use Calculatable; + + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the discount + * @var int $offerId The id of the offer this discount is linked to + * @var string $title The title of the discount + * @var string $description The description of the discount + * @var float $value The actual discount + * @var float $vat The percentage of VAT to calculate on this discount + */ + protected $pdo, $offerId, $id, $title, $description, $value, $vat; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the discount to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the discount could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."discount` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The discount with id '$id' could not be found."); + } + $discount = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $discount['id']; + $this->offerId = $discount['offerId']; + $this->title = $discount['title']; + $this->description = $discount['description']; + $this->value = $discount['value']; + $this->vat = $discount['VAT_percentage']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the discount + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the offer that this discount is linked to + * + * @return int The ID + */ + public function getOfferId() { + return $this->offerId; + } + + /** + * Get the offer that this discount is linked to + * + * @return offer The offer + */ + public function getOffer() { + return new Offer($this->pdo, $this->offerId); + } + + /** + * Get the title of the discount + * + * @return string The title + */ + public function getTitle() { + return $this->title; + } + + /** + * Set the title of the discount + * + * @param string $title The new title for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setTitle($title) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."discount` SET `title`=? WHERE `id`=?"); + $stmt->execute(array($title, $this->id)); + if ($stmt->rowCount() == 1) { + $this->title = $title; + return true; + } else { + return false; + } + } + + /** + * Get the description of the discount + * + * @param bool $parseMarkdown Whether or not to parse markdown + * + * @return string The description + */ + public function getDescription($parseMarkdown = true) { + if ($parseMarkdown) { + $pd = new Parsedown; + return $pd->text($this->description); + } else { + return $this->description; + } + } + + /** + * Set the description of the discount + * + * @param string $description The new description for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setDescription($description) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."discount` SET `description`=? WHERE `id`=?"); + $stmt->execute(array($description, $this->id)); + if ($stmt->rowCount() == 1) { + $this->description = $description; + return true; + } else { + return false; + } + } + + /** + * Get the value of the discount + * + * @return float The value + */ + public function getValue() { + return $this->value; + } + + /** + * Set the value of the discount + * + * @param float $value The new value for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setValue($value) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."discount` SET `value`=? WHERE `id`=?"); + $stmt->execute(array($value, $this->id)); + if ($stmt->rowCount() == 1) { + $this->value = $value; + return true; + } else { + return false; + } + } + + /** + * Get the VAT percentage of the discount + * + * @return float The VAT percentage + */ + public function getVAT() { + return $this->vat; + } + + /** + * Set the VAT percentage of the discount + * + * @param float $vat The new VAT percentage for the discount + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setVAT($vat) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."discount` SET `VAT_percentage`=? WHERE `id`=?"); + $stmt->execute(array($vat, $this->id)); + if ($stmt->rowCount() == 1) { + $this->vat = $vat; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + protected function calculateSubtotal() { + return - $this->value; + } + + protected function calculateVAT() { + return $this->calculateSubtotal() * $this->getVAT() / 100; + } + + /** + * Remove this discount from the database + * + * If this doesn't succeed (i.e. false is returned), that means the discount was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."discount` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} diff --git a/classes/FPDF.license.txt b/classes/FPDF.license.txt new file mode 100644 index 0000000..fd811c6 --- /dev/null +++ b/classes/FPDF.license.txt @@ -0,0 +1,6 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software to use, copy, modify, distribute, sublicense, and/or sell +copies of the software, and to permit persons to whom the software is furnished +to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. \ No newline at end of file diff --git a/classes/File.php b/classes/File.php new file mode 100644 index 0000000..656ac5e --- /dev/null +++ b/classes/File.php @@ -0,0 +1,148 @@ +. + */ + +/** + * An interface to the file table in the database + */ +class File { + /** + * @var PDO $pdo The PDO class for database communication + * @var int $id The id of the file + * @var string $filename The relative path to the file + */ + protected $pdo, $id, $filename; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the file to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the file could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."file` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The file with id '$id' could not be found."); + } + $file = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $file['id']; + $this->filename = $file['filename']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the file + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the relative filename of the file + * + * @see file::getFilenamePath To get the full internal path to the file + * @see file::getFilenameURI To get the full external path to the file + * + * @return string The filename + */ + public function getFilename() { + return $this->filename; + } + + /** + * Get the full internal path to the file + * + * @see file::getFilename To get the relative filename + * @see file::getFilenameURI To get the full external path to the file + * + * @return string The path + */ + public function getFilenamePath() { + return Constants::files_folder . $this->filename; + } + + /** + * Get the full external path to the file + * + * @see file::getFilename To get the relative filename + * @see file::getFilenamePath To get the full internal path to the file + * + * @return string The URI + */ + public function getFilenameURI() { + return Constants::files_folder_external . $this->filename; + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Move this file to the trash and delete all records for it + * + * Physically, this moves the file to a trash folder + * Then, the file will be removed from the file table in the database + * Any appendices linking to this file with fileId will have fileId NULL + * Any offers linking to this file with invoice_fileId will have invoice_fileId NULL + * + * @throws PDOException If there's something wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + // Try to move the file to trash + $newname = pathinfo($this->filename, PATHINFO_FILENAME) . '--' . date('Y-m-d.H.i.s.') . pathinfo($this->filename, PATHINFO_EXTENSION); + $newdir = pathinfo($this->getFilenamePath(), PATHINFO_DIRNAME) . '/' . Constants::files_folder_trash . '/'; + if (!file_exists($newdir)) { + if (!mkdir($newdir)) { + return false; + } + } + if (!(@rename($this->getFilenamePath(), $newdir . $newname))) { + return false; + } + + // Remove offers linked by invoice_fileId + $this->pdo->query("UPDATE `".Constants::db_prefix."offer` SET `invoice_fileId`=NULL WHERE `invoice_fileId`={$this->id}"); + + // Remove the record of the file + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."file` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() == 1) { + return true; + } else { + return false; + } + } +} diff --git a/classes/Model.php b/classes/Model.php index 37c719a..68f045e 100644 --- a/classes/Model.php +++ b/classes/Model.php @@ -140,6 +140,6 @@ abstract class Model { * @return string The database table */ private function table() { - return constants::db_prefix . $this->table; + return Constants::db_prefix . $this->table; } } diff --git a/classes/Offer.php b/classes/Offer.php new file mode 100644 index 0000000..d08091b --- /dev/null +++ b/classes/Offer.php @@ -0,0 +1,747 @@ +. + */ + +/** + * An interface to the offer table in the database + */ +class Offer { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the offer + * @var int $contactId The id of the contact this offer is linked to + * @var int $start_date A UNIX timestamp of the start date + * @var int $end_date A UNIX timestamp of the end date + * @var int $invoice_date A UNIX timestamp of the invoice date + * @var bool $accepted Whether the offer is accepted or not + * @var null|int $invoice_fileId If an invoice has been generated, an the id of the file + */ + protected $pdo, $id, $contactId, $start_date, $end_date, $invoice_date, $accepted, $invoice_fileId; + + const SUBTOTAL = 1; + const VAT = 2; + const TOTAL = 3; + + /** + * Create a new instance + * + * Blah + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the offer to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the offer could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."offer` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The offer with id '$id' could not be found."); + } + $offer = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $offer['id']; + $this->contactId = $offer['contactId']; + $this->start_date = strtotime($offer['start_date']); + $this->end_date = strtotime($offer['end_date']); + $this->invoice_date = strtotime($offer['invoice_date']); + $this->accepted = (bool) $offer['accepted']; + $this->invoice_fileId = $offer['invoice_fileId']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the offer + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the contact that this offer is linked to + * + * @see offer::getContact() This function returns the contact as an instance of the object class + * + * @return int The ID + */ + public function getContactId() { + return $this->contactId; + } + + /** + * Get the contact that this offer is linked to + * + * @see offer::getContactId() This function returns just the id + * + * @return contact The contact + */ + public function getContact() { + return new Contact($this->pdo, $this->contactId); + } + + /** + * Get all assignment ids for this offer + * + * @see offer::getAssignments() This funtion returns instances of the assignment class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getAssignmentIds() { + $ids = array(); + $assignments = $this->pdo->query("SELECT `id` FROM `".Constants::db_prefix."assignment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($assignments as $assignment) { + $ids[] = $assignment['id']; + } + return $ids; + } + + /** + * Get all assignments for this offer + * + * @see offer::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class + * + * @throws PDOException If something went wrong with the database + * + * @return assignment[] An array indexed by id of instances of the assignment class + */ + public function getAssignments() { + $ids = $this->getAssignmentIds(); + $assignments = array(); + foreach ($ids as $id) { + $assignments[$id] = new Assignment($this->pdo, $id); + } + return $assignments; + } + + /** + * Get all discount ids for this offer + * + * @see offer::getDiscounts() This funtion returns instances of the discount class instead of just the ids + * + * @throws PDOException Is something went wrong with the database + * + * @return int[] The ids + */ + public function getDiscountIds() { + $ids = array(); + $discounts = $this->pdo->query("SELECT `id` FROM `".Constants::db_prefix."discount` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($discounts as $discount) { + $ids[] = $discount['id']; + } + return $ids; + } + + /** + * Get all discounts for this offer + * + * @see offer::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class + * + * @throws PDOException If something went wrong with the database + * + * @return discount[] An array indexed by id of instances of the discount class + */ + public function getDiscounts() { + $ids = $this->getDiscountIds(); + $discounts = array(); + foreach ($ids as $id) { + $discounts[$id] = new Discount($this->pdo, $id); + } + return $discounts; + } + + /** + * Get the payment id for this offer + * + * @see offer::getPayment() This funtion returns an instance of the payment class instead of just the id + * + * @throws PDOException Is something went wrong with the database + * + * @return int|null The id, or null if no payment exists + */ + public function getPaymentId() { + $ids = array(); + $payments = $this->pdo->query("SELECT `id` FROM `".Constants::db_prefix."payment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); + foreach ($payments as $payment) { + return $payment['id']; + } + return null; + } + + /** + * Get the payment for this offer + * + * @see offer::getPaymentId() This function returns just the id of the payment, and not an instance of the payment class + * + * @throws PDOException If something went wrong with the database + * + * @return payment|null The payment, or null if it does not exist + */ + public function getPayment() { + $id = $this->getPaymentId(); + if (is_null($id)) { + return null; + } else { + return new Payment($this->pdo, $id); + } + } + + /** + * Get the start date of the assignment + * + * @return int The start date as a UNIX timestamp + */ + public function getStartDate() { + return $this->start_date; + } + + /** + * Set the start date of the assignment + * + * @param int $start_date The new start date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setStartDate($start_date) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."offer` SET `start_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $start_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->start_date = $start_date; + return true; + } else { + return false; + } + } + + /** + * Get the end date of the assignment + * + * @return int The end date as a UNIX timestamp + */ + public function getEndDate() { + return $this->end_date; + } + + /** + * Set the end date of the assignment + * + * @param int $end_date The new end date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setEndDate($end_date) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."offer` SET `end_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $end_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->end_date = $end_date; + return true; + } else { + return false; + } + } + + /** + * Get the invoice date of the assignment + * + * @return int The invoice date as a UNIX timestamp + */ + public function getInvoiceDate() { + return $this->invoice_date; + } + + /** + * Set the invoice date of the assignment + * + * @param int $invoice_date The new invoice date for the assignment as a UNIX timestamp + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setInvoiceDate($invoice_date) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."offer` SET `invoice_date`=? WHERE `id`=?"); + $stmt->execute(array(date('Y-m-d', $invoice_date), $this->id)); + if ($stmt->rowCount() == 1) { + $this->invoice_date = $invoice_date; + return true; + } else { + return false; + } + } + + /** + * Get the date the payment was received + * + * @return int|null The date as a UNIX timestamp, or null if it wasn't received yet + */ + public function getPaymentReceived() { + $payment = $this->getPayment(); + if (is_null($payment)) { + return null; + } else { + return $payment->getDate(); + } + } + + /** + * Check if the offer is accepted or not + * + * @return bool True if the offer is accepted, false if not + */ + public function isAccepted() { + return $this->accepted; + } + + /** + * Toggle the `accepted' status of the offer + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function toggleAccepted() { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."offer` SET `accepted`=? WHERE `id`=?"); + $new_value = !$this->accepted; + $stmt->execute(array($new_value, $this->id)); + if ($stmt->rowCount() == 1) { + $this->accepted = $new_value; + return true; + } else { + return false; + } + } + + /** + * Get the ID of the file that the invoice of this offer is linked to + * + * @see offer::getInvoiceFile() This function returns the file as an instance of the file class + * + * @return int The ID + */ + public function getInvoiceFileId() { + return $this->invoice_fileId; + } + + /** + * Get the file that the invoice this offer is linked to + * + * @see offer::getInvoiceId() This function returns just the id + * + * @return file|null The file, or null if it doesn't exist + */ + public function getInvoiceFile() { + if ($this->invoice_fileId != null) { + return new File($this->pdo, $this->invoice_fileId); + } else { + return null; + } + } + + /** + * Set the invoice file id of the assignment + * + * @param int $invoice_fileId The new invoice file id for the assignment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setInvoiceFileId($invoice_fileId) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."offer` SET `invoice_fileId`=? WHERE `id`=?"); + $stmt->execute(array($invoice_fileId, $this->id)); + if ($stmt->rowCount() == 1) { + $this->invoice_fileId = $invoice_fileId; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Calculate a handy number about the invoice + * + * Subtotal: the sum of the prices of the assignments excl. VAT + * + * VAT: the sum of all the VAT from all the assignments + * + * Total: the sum of subtotal and total + * + * @param int $what Any of offer::SUBTOTAL, offer::VAT and offer::TOTAL + * @param int $round How many decimals to round the result on + * @param bool $format Whether to format the number nicely (for output) or not (for calculations) + * + * @throws PDOException If something went wrong with the database + * + * @return float|bool The calculated value rounded to $round decimals, or false on incorrect input + */ + public function calculate($what = self::TOTAL, $round = 2, $format = true) { + $return = 0; + switch ($what) { + case self::SUBTOTAL: + foreach ($this->getAssignments() as $assignment) { + $return += $assignment->calculate(assignment::SUBTOTAL, $round + 1, false); + } + foreach ($this->getDiscounts() as $discount) { + $return += $discount->calculate(discount::SUBTOTAL, $round + 1, false); + } + break; + case self::VAT: + $assignments = $this->getAssignments(); + foreach ($assignments as $assignment) { + $return += $assignment->calculate(assignment::VAT, $round + 1, false); + } + foreach ($this->getDiscounts() as $discount) { + $return += $discount->calculate(discount::VAT, $round + 1, false); + } + break; + case self::TOTAL: + $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); + break; + default: + return false; + } + if ($format) { + return number_format($return, 2); + } else { + return round($return, 2); + } + } + + /** + * Remove this offer from the database + * + * If this doesn't succeed (i.e. false is returned), that means the offer was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."offer` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } + + /** + * Make a new assignment linked to this order + * + * @param string $title The title for this assignment + * @param string $description The description for this assignment + * @param int $hours The amount of hours to work on this assignment + * @param float $price_per_hour The price per hour on this assignment + * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return assignment A new instance of the assignment class containing the new assignment + */ + public function createAssignment($title, $description, $hours, $price_per_hour, $vat) { + $stmt = $this->pdo->prepare("INSERT INTO `".Constants::db_prefix."assignment` (`offerId`,`title`,`description`,`hours`,`price_per_hour`,`VAT_percentage`) VALUES (?,?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $title, + $description, + $hours, + $price_per_hour, + $vat + )); + if ($stmt->rowCount() == 1) { + return new Assignment($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } + + /** + * Make a new discount linked to this order + * + * @param string $title The title for this discount + * @param string $description The description for this discount + * @param float $value The value for this discount + * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return discount A new instance of the discount class containing the new discount + */ + public function createDiscount($title, $description, $value, $vat) { + $stmt = $this->pdo->prepare("INSERT INTO `".Constants::db_prefix."discount` (`offerId`,`title`,`description`,`value`,`VAT_percentage`) VALUES (?,?,?,?,?)"); + $stmt->execute(array( + $this->id, + $title, + $description, + $value, + $vat + )); + if ($stmt->rowCount() == 1) { + return new Discount($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } + + /** + * Add a payment for this order + * + * @param string $date Optional: the date for the payment + * + * @throws PDOException If something went wrong with the database + * @throws Exception If there was a problem with the input + * + * @return payment A new instance of the payment class containing the new payment + */ + public function createPayment($date=null) { + $date = is_null($date) ? time() : $date; + $stmt = $this->pdo->prepare("INSERT INTO `".Constants::db_prefix."payment` (`offerId`,`date`) VALUES (?,?)"); + $stmt->execute([$this->id, date('Y-m-d H:i:s', $date)]); + if ($stmt->rowCount() == 1) { + return new Payment($this->pdo, $this->pdo->lastInsertId()); + } else { + $error = $stmt->errorInfo(); + throw new Exception($error[2]); + } + } + + /** + * Generate a PDF invoice + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the file could not be written or an other error occured + * + * @return file An instance of the file class with information on the invoice file generated + */ + public function generateInvoice() { + // Check if we already have a file + $file = $this->getInvoiceFile(); + if (!($file instanceof file)) { + // If not, create a new file + $i = 1; + do { + $invoice_nr = date('Y',$this->invoice_date) . str_pad($i++, 2, '0', STR_PAD_LEFT); + $filename = 'invoice-' . $invoice_nr . '.pdf'; + } while (file_exists(Constants::files_folder . $filename)); + $file = BusinessAdmin::createFile($this->pdo, $filename); + + $this->setInvoiceFileId($file->getId()); + } else { + $invoice_nr = str_replace(array('invoice-','.pdf'), array('',''), $file->getFilename()); + } + + $list = array(); + foreach ($this->getAssignments() as $assignment) + $list[] = array( + $assignment->getTitle(), + $assignment->getPricePerHour() * $assignment->getHours(), + $assignment->getVAT() . "%", + $assignment->getPricePerHour() * $assignment->getHours() * (1 + $assignment->getVAT() / 100) + ); + foreach ($this->getDiscounts() as $discount) + $list[] = array( + $discount->getTitle(), + $discount->calculate(discount::SUBTOTAL), + $discount->getVAT() . "%", + $discount->calculate(discount::TOTAL) + ); + + $pdf = new Correspondence(); + $pdf->SetContact($this->getContact()); + $pdf->SetTitle($pdf->_('invoice') . ' ' . $invoice_nr); + $pdf->AddPage(); + $pdf->correspondenceHeader(); + + $pdf->SetY(100); + $pdf->SetFont('','B',14); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->Cell(60,6, $pdf->_('invoice'),'B'); + $pdf->SetTextColor(0); + $pdf->Ln(); + + $width = array(90,25,20,25); + $subtotal = 0; + $btw = array(); + $total = 0; + + // Header + + $pdf->SetFont('','',9); + $pdf->Cell(60,4); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('invoice-date')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,date("d-m-Y", $this->invoice_date)); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('invoice-nr')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,$invoice_nr); + $pdf->Ln(); + $pdf->SetFont('','B'); + $pdf->Cell(30,4.5,$pdf->_('due-date')); + $pdf->SetFont('',''); + $pdf->Cell(50,4.5,date("d-m-Y",$this->invoice_date+3600*24*30)); + $pdf->Ln(); + $pdf->Cell(60,4.5,'','B'); + $pdf->Ln(); + + $pdf->SetY(140); + + // Table + + $pdf->SetFont('','B',11); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->Cell($width[0],7,$pdf->_('description'),'B'); + $pdf->Cell($width[1],7,$pdf->_('price-excl'),'B',0,'R'); + $pdf->Cell($width[2],7,$pdf->_('vat'),'B',0,'R'); + $pdf->Cell($width[3],7,$pdf->_('price-incl'),'B',0,'R'); + $pdf->SetTextColor(0); + $pdf->Ln(); + + $pdf->SetFont('',''); + foreach ($list as $row) { + $x = $pdf->getX(); + $y = $pdf->getY(); + $pdf->MultiCell($width[0],6,iconv('utf-8', 'iso-8859-1', $row[0]),0,'L'); + $newy = $pdf->getY(); + $pdf->SetXY($x + $width[0], $y); + $pdf->Cell($width[1],6,correspondence::valuta().number_format($row[1],2),'',0,'R'); + $pdf->Cell($width[2],6,round($row[2],0) . '%','',0,'R'); + $pdf->Cell($width[3],6,correspondence::valuta().number_format($row[3],2),'',0,'R'); + $pdf->Ln(); + $pdf->SetY($newy); + $pdf->addPageIfOnEnd(); + $subtotal += $row[1]; + if (!isset($btw[$row[2]])) $btw[$row[2]] = 0; + $btw[$row[2]] += $row[3] - $row[1]; + } + $total = $subtotal; + foreach ($btw as $m) { + $total += $m; + } + + $pdf->Cell(array_sum($width),5,'','T'); + $pdf->Ln(); + $pdf->Cell(array_sum($width),5); + $pdf->Ln(); + + $pdf->Cell($width[0],7); + $pdf->SetFont('','B'); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('amount')); + $pdf->SetFont('',''); + $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::SUBTOTAL),'',0,'R'); + $pdf->Ln(); + + foreach ($btw as $p => $m) { + $pdf->Cell($width[0],7); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('vat') . ' '.round($p,0).'%'); + $pdf->Cell($width[3],7,correspondence::valuta() . number_format($m,2),'',0,'R'); + $pdf->Ln(); + } + + $pdf->Cell(array_sum($width),5); + $pdf->Ln(); + + $pdf->Cell($width[0],7); + $pdf->SetFont('','B'); + $pdf->Cell($width[1] + $width[2],7,$pdf->_('total')); + $pdf->SetFont('',''); + $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::TOTAL),'T',0,'R'); + $pdf->Ln(); + + // Footer + + $pdf->Ln(); + $pdf->addPageIfOnEnd(); + if ($pdf->GetY() < 230) { + $pdf->SetY(230); + } + $oldY = $pdf->GetY(); + $pdf->Cell(45,20,'',1); + $pdf->Cell(12.5,20); + $pdf->Cell(45,20,'',1); + $pdf->Cell(12.5,20); + $pdf->Cell(45,20,'',1); + + $pdf->SetFont('','B',10); + $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); + $pdf->SetY($oldY + 3); + $pdf->Cell(5,5); + $pdf->Cell(40,5,$pdf->_('iban')); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$pdf->_('invoice-nr')); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$pdf->_('amount-due')); + $pdf->SetTextColor(0); + + $pdf->SetFont('','',8); + $pdf->Ln(); + $pdf->Ln(); + $oldY = $pdf->GetY(); + + $pdf->Cell(5,5); + $pdf->Cell(40,5, Constants::invoice_iban); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,$invoice_nr); + $pdf->Cell(17.5,5); + $pdf->Cell(40,5,correspondence::valuta() . $this->calculate(self::TOTAL)); + + $pdf->SetY($oldY + 14); + + $pdf->SetFontSize(7); + $pdf->Cell(160,5,$pdf->_('request'),0,0,'C'); + $pdf->Ln(); + $pdf->Cell(160,5,str_replace('%%', Constants::invoice_bic, $pdf->_('biccode')),0,0,'C'); + + if (file_exists($file->getFilenamePath())) { + unlink($file->getFilenamePath()); + } + $pdf->Output($file->getFilenamePath(),'F'); + chmod($file->getFilenamePath(),0644); + + return $file; + } +} diff --git a/classes/Payment.php b/classes/Payment.php new file mode 100644 index 0000000..11c57a3 --- /dev/null +++ b/classes/Payment.php @@ -0,0 +1,142 @@ +. + */ + +/** + * An interface to the payment table in the database + */ +class Payment { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the payment + * @var int $offerId The id of the offer this payment is linked to + * @var int $date A unix timestamp describing the date of the payment + */ + protected $pdo, $offerId, $id, $date; + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the payment to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the payment could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."payment` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The payment with id '$id' could not be found."); + } + $payment = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $payment['id']; + $this->offerId = $payment['offerId']; + $this->date = strtotime($payment['date']); + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the payment + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the ID of the offer that this payment is linked to + * + * @return int The ID + */ + public function getOfferId() { + return $this->offerId; + } + + /** + * Get the offer that this payment is linked to + * + * @return offer The offer + */ + public function getOffer() { + return new Offer($this->pdo, $this->offerId); + } + + /** + * Get the date of the payment + * + * @return int A unix timestamp describing the date of the payment + */ + public function getDate() { + return $this->date; + } + + /** + * Set the date of the payment + * + * @param int $date The new date for the payment + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function setDate($date) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."payment` SET `date`=? WHERE `id`=?"); + $stmt->execute([date('Y-m-d H:i:s', $date), $this->id]); + if ($stmt->rowCount() == 1) { + $this->date = $date; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Remove this payment from the database + * + * If this doesn't succeed (i.e. false is returned), that means the payment was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."payment` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} diff --git a/classes/Response.php b/classes/Response.php new file mode 100644 index 0000000..f37b6e9 --- /dev/null +++ b/classes/Response.php @@ -0,0 +1,112 @@ +. + */ + +/** + * Provides a standard to base all responses to be called with AJAX on + */ +class Response { + /** The variable to keep the response in until output */ + private $response; + /** The variable to keep the HTTP response code in until output */ + private $http_response_code; + + /** + * Create a new instance + */ + public function __construct() { + $this->response = array(); + $this->http_response_code = 200; + } + + /** + * Set a variable of the response + * + * @param string $name The name of the variable to set + * @param string $value The (new) value for the variable + */ + public function __set($name, $value) { + $this->response[$name] = $value; + } + + /** + * Get a variable of the response + * + * @param string $name The name of the variable to get + * + * @return mixed The value of the variable + */ + public function __get($name) { + return $this->response[$name]; + } + + /** + * Check if a variable of the response is set + * + * @param string $name The name of the variable to check + * + * @return bool True if the variable exists, false otherwise + */ + public function __isset($name) { + return isset($this->response[$name]); + } + + /** + * Unset a variable of the response + * + * @param string $name The variable to unset + */ + public function __unset($name) { + unset($this->response[$name]); + } + + /** + * Get or set the HTTP response code + * + * If a parameter is provided, it is used as the new HTTP response code, and a bool is returned for success or failure. Otherwise, the current one is returned. + * + * @param int $code The new code + * + * @return int|bool True on successful change, false on unsuccesful change, int when the current code is returned + */ + public function http_response_code($code = null) { + if ($code === null) { + return $this->http_response_code; + } else { + if (http_response_code($code)) { + $this->http_response_code = $code; + return true; + } else { + return false; + } + } + } + + /** + * Output the response in json + * + * @return string The response in json format + */ + public function getJson() { + return json_encode($this->response); + } +} diff --git a/classes/User.php b/classes/User.php new file mode 100644 index 0000000..0569433 --- /dev/null +++ b/classes/User.php @@ -0,0 +1,198 @@ +. + */ + +/** + * An interface to the user table in the database + */ +class User { + /** + * @var pdo $pdo The PDO class for database communication + * @var int $id The id of the user + * @var string $username The username of the user + * @var string $password The (hashed) password of the user + */ + protected $pdo, $id, $username, $password; + + /** + * Generate a random password + * + * @return string The password + */ + public static function generateRandomPassword() { + return preg_replace('/[^\w]/', '', + base64_encode(bin2hex(openssl_random_pseudo_bytes(4)))); + } + + /** + * Hash a password + * + * @param string $password The password to be hashed + * @param int $cost The password cost + * + * @return string The hashed password + */ + public static function hash($password, $cost=null) { + return password_hash( + $password, + Constants::password_algo, + ['cost' => is_null($cost) ? Constants::password_cost : $cost] + ); + } + + /** + * Create a new instance + * + * @param PDO $pdo The PDO class, to access the database + * @param int $id The id of the user to fetch + * + * @throws PDOException If something went wrong with the database + * @throws Exception If the user could not be found + */ + public function __construct($pdo, $id) { + $this->pdo = $pdo; + + $stmt = $this->pdo->prepare("SELECT * FROM `".Constants::db_prefix."user` WHERE `id`=?"); + $stmt->execute(array($id)); + if ($stmt->rowCount() == 0) { + throw new Exception("The user with id '$id' could not be found."); + } + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + $this->id = $user['id']; + $this->username = $user['username']; + $this->password = $user['password']; + } + + //------------------------------------------------------------------------------ + // Getters and setters + //------------------------------------------------------------------------------ + + /** + * Get the ID of the user + * + * @return int The ID + */ + public function getId() { + return $this->id; + } + + /** + * Get the username of the user + * + * @return string The username + */ + public function getUsername() { + return $this->username; + } + + /** + * Set the username of the user + * + * @param string $username The new username for the user + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setName($username) { + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."user` SET `username`=? WHERE `id`=?"); + $stmt->execute(array($username, $this->id)); + if ($stmt->rowCount() == 1) { + $this->username = $username; + return true; + } else { + return false; + } + } + + /** + * Set the password of the user + * + * @param string $password The new password for the user + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on succes, false on failure + */ + public function setPassword($password) { + $password = self::hash($password); + $stmt = $this->pdo->prepare("UPDATE `".Constants::db_prefix."user` SET `password`=? WHERE `id`=?"); + $stmt->execute(array($password, $this->id)); + if ($stmt->rowCount() == 1) { + $this->password = $password; + return true; + } else { + return false; + } + } + + //------------------------------------------------------------------------------ + // Other functions + //------------------------------------------------------------------------------ + + /** + * Check if a user has administrator rights + * + * @return bool True iff the user has administrator rights + */ + public function isAdmin() { + return in_array($this->getId(), Constants::user_admins); + } + + /** + * Verify a password + * + * @param string $password The password to verify + * + * @return bool True iff the password can be accepted + */ + public function verifyPassword($password) { + if (!password_verify($password, $this->password)) { + return false; + } + if (password_needs_rehash($this->password, Constants::password_algo, + ['cost' => Constants::password_cost])) { + $this->setPassword($password); + } + return true; + } + + /** + * Remove this user from the database + * + * If this doesn't succeed (i.e. false is returned), that means the user was removed manually or by another instance of this class + * + * @throws PDOException If something went wrong with the database + * + * @return bool True on success, false on failure + */ + public function delete() { + $stmt = $this->pdo->prepare("DELETE FROM `".Constants::db_prefix."user` WHERE `id`=?"); + $stmt->execute(array($this->id)); + if ($stmt->rowCount() != 1) { + return false; + } else { + return true; + } + } +} diff --git a/classes/assignment.php b/classes/assignment.php deleted file mode 100644 index 25b6432..0000000 --- a/classes/assignment.php +++ /dev/null @@ -1,287 +0,0 @@ -. - */ - -/** - * An interface to the assignment table in the database - */ -class assignment { - use Calculatable; - - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the assignment - * @var int $offerId The id of the offer this assignment is linked to - * @var string $title The title of the assignment - * @var string $description The description of the assignment - * @var int $hours The amount of hours of the assignment - * @var float $price_per_hour The price per hour for this assignment, in your valuta - * @var float $vat The percentage of VAT to calculate on this assignment - */ - protected $pdo, $offerId, $id, $title, $description, $hours, $price_per_hour, $vat; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the assignment to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the assignment could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."assignment` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The assignment with id '$id' could not be found."); - } - $assignment = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $assignment['id']; - $this->offerId = $assignment['offerId']; - $this->title = $assignment['title']; - $this->description = $assignment['description']; - $this->hours = $assignment['hours']; - $this->price_per_hour = $assignment['price_per_hour']; - $this->vat = $assignment['VAT_percentage']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the assignment - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the offer that this assignment is linked to - * - * @return int The ID - */ - public function getOfferId() { - return $this->offerId; - } - - /** - * Get the offer that this assignment is linked to - * - * @return offer The offer - */ - public function getOffer() { - return new offer($this->pdo, $this->offerId); - } - - /** - * Get the title of the assignment - * - * @return string The title - */ - public function getTitle() { - return $this->title; - } - - /** - * Set the title of the assignment - * - * @param string $title The new title for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setTitle($title) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `title`=? WHERE `id`=?"); - $stmt->execute(array($title, $this->id)); - if ($stmt->rowCount() == 1) { - $this->title = $title; - return true; - } else { - return false; - } - } - - /** - * Get the description of the assignment - * - * @param bool $parseMarkdown Whether or not to parse markdown - * - * @return string The description - */ - public function getDescription($parseMarkdown = true) { - if ($parseMarkdown) { - $pd = new Parsedown; - return $pd->text($this->description); - } else { - return $this->description; - } - } - - /** - * Set the description of the assignment - * - * @param string $description The new description for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setDescription($description) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `description`=? WHERE `id`=?"); - $stmt->execute(array($description, $this->id)); - if ($stmt->rowCount() == 1) { - $this->description = $description; - return true; - } else { - return false; - } - } - - /** - * Get the amount of hours of the assignment - * - * @return int The amount of hours - */ - public function getHours() { - return $this->hours; - } - - /** - * Set the amount of hours of the assignment - * - * @param int $hours The new amount hours for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setHours($hours) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `hours`=? WHERE `id`=?"); - $stmt->execute(array($hours, $this->id)); - if ($stmt->rowCount() == 1) { - $this->hours = $hours; - return true; - } else { - return false; - } - } - - /** - * Get the price per hour of the assignment - * - * @return float The price per hour - */ - public function getPricePerHour() { - return $this->price_per_hour; - } - - /** - * Set the price per hour of the assignment - * - * @param float $price_per_hour The new price per hour for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPricePerHour($price_per_hour) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `price_per_hour`=? WHERE `id`=?"); - $stmt->execute(array($price_per_hour, $this->id)); - if ($stmt->rowCount() == 1) { - $this->price_per_hour = $price_per_hour; - return true; - } else { - return false; - } - } - - /** - * Get the VAT percentage of the assignment - * - * @return float The VAT percentage - */ - public function getVAT() { - return $this->vat; - } - - /** - * Set the VAT percentage of the assignment - * - * @param float $vat The new VAT percentage for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setVAT($vat) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."assignment` SET `VAT_percentage`=? WHERE `id`=?"); - $stmt->execute(array($vat, $this->id)); - if ($stmt->rowCount() == 1) { - $this->vat = $vat; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - protected function calculateSubtotal() { - return $this->getHours() * $this->getPricePerHour(); - } - - protected function calculateVAT() { - return $this->calculateSubtotal() * $this->getVAT() / 100; - } - - /** - * Remove this assignment from the database - * - * If this doesn't succeed (i.e. false is returned), that means the assignment was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."assignment` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} diff --git a/classes/client.php b/classes/client.php deleted file mode 100644 index 46e2da2..0000000 --- a/classes/client.php +++ /dev/null @@ -1,108 +0,0 @@ -. - */ - -/** - * An interface to the client table in the database - */ -class client extends Model { - public - $table = 'client', - $fillable_columns = ['name']; - - /** - * Get all contact ids for this client - * - * @see client::getContacts() This funtion returns instances of the contact class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getContactIds() { - $ids = array(); - $contacts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."contact` WHERE `clientId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($contacts as $contact) { - $ids[] = $contact['id']; - } - return $ids; - } - - /** - * Get all contacts for this client - * - * @see client::getContactIds() This function returns just the ids of the contacts, and not instances of the contact class - * - * @throws PDOException If something went wrong with the database - * - * @return contact[] An array indexed by id of instances of the contact class - */ - public function getContacts() { - $ids = $this->getContactIds(); - $contacts = array(); - foreach ($ids as $id) { - $contacts[$id] = new contact($this->pdo, $id); - } - return $contacts; - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Make a new contact for this client - * - * @param string $name The name for this contact - * @param string $email The email for this contact - * @param string $address The first address line of this contact (normally street and house number) - * @param string $address_2 The second address line of this contact - * @param string $postal_code The postal code for this contact - * @param string $city The city for this contact - * @param string $state The state for this contact - * @param string $country The country for this contact - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return contact A new instance of the contact class containing the new contact - */ - public function createContact($name, $email, $address, $address_2, $postal_code, $city, $country) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."contact` (`clientId`,`name`,`email`,`address`,`address_2`,`postal_code`,`city`,`country`) VALUES (?,?,?,?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $name, - $email, - $address, - $address_2, - $postal_code, - $city, - $country - )); - if ($stmt->rowCount() == 1) { - return new contact($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } -} diff --git a/classes/constants.php b/classes/constants.php deleted file mode 100644 index 663d603..0000000 --- a/classes/constants.php +++ /dev/null @@ -1,84 +0,0 @@ -. - */ - -/** - * A class for some constants - */ -class constants { - /** @const db_prefix A prefix to add to the tables in the database (leave empty for none) */ - const db_prefix = ''; - - /** @const files_folder The folder to store all files (appendices, invoices, etc.) in; with a trailing slash */ - const files_folder = '/var/www/localhost/BusinessAdmin/files/'; - /** @const files_folder_external The external URI to this folder; with a trailing slash */ - const files_folder_external = 'http://localhost/BusinessAdmin/files/'; - /** @const files_folder_trash The folder inside files_folder to use a trash, without any trailing slashes */ - const files_folder_trash = 'trash'; - - /** @const url_external The external URI to this folder; with a trailing slash */ - const url_external = 'http://localhost/BusinessAdmin/'; - /** @const url_internal The URI without the domain name; with a slash at the beginning but not at the end */ - const url_internal = '/BusinessAdmin'; - - /** @const my_name Name of this control panel */ - const my_name = 'BusinessAdmin'; - - /** - * @const invoice_name Your name or the name of your business - * @const invoice_address_1 First address line - * @const invoice_address_2 Second address line - * @const invoice_address_3 Third address line - * @const invoice_tax_nr Your tax number - * @const invoice_iban Your IBAN number - * @const invoice_bic The BIC code of your bank - * @const invoice_tel_nr Your telephone number - * @const invoice_email Your email address - * @const invoice_valuta The valuta symbol (will be placed in front of amounts). You can use a symbol like $ or a code like USD - */ - const invoice_name = 'BusinessAdmin'; - const invoice_address_1 = 'My Street 1'; - const invoice_address_2 = '12345 My City'; - const invoice_address_3 = 'My Country'; - const invoice_tax_nr = 'XX123456789A00'; - const invoice_iban = 'XX00 ABCD 1234 5678 90'; - const invoice_bic = 'XXXX XXXX'; - const invoice_tel_nr = '+31 6 1234 5678'; - const invoice_email = 'my-email@domain.tld'; - const invoice_valuta = '€'; - - /** @const fa_valuta see http://fontawesome.io/icons/#currency; the fa- postfix for valuta */ - const fa_valuta = 'eur'; - - /** @const user_admins The user ids that have administrator rights (creating and deleting users) */ - const user_admins = [1]; - - /** - * @const password_algo Algorithm for the password_hash function. - * @const password_cost Cost for the password_hash function. Run install?password_cost to benchmark your system - */ - const password_algo = PASSWORD_DEFAULT; - const password_cost = 10; - - /** @const version Version of BusinessAdmin. Don't change this yourself! */ - const version = '0.4.2'; -} diff --git a/classes/contact.php b/classes/contact.php deleted file mode 100644 index 7741c17..0000000 --- a/classes/contact.php +++ /dev/null @@ -1,384 +0,0 @@ -. - */ - -/** - * An interface to the contact table in the database - */ -class contact { - /** - * @var PDO $pdo The PDO class for database communication - * @var int $id The id of the contact - * @var int $clientId The id of the client the contact is linked to - * @var string $name The name of the contact - * @var string $email The email address of the contact - * @var string $address The first address line (normally street and house number) of the contact - * @var string $address_2 The second address line (can be null) - * @var string $postal_code The postal code of the contact - * @var string $city The city of the contact - * @var string $country The country of the contact - * @var string $language The language of the contact - */ - protected $pdo, $id, $clientId, $name, $email, $address, $postal_code, $city, $country, $language; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the contact to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the contact could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."contact` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The contact with id '$id' could not be found."); - } - $contact = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $contact['id']; - $this->clientId = $contact['clientId']; - $this->name = $contact['name']; - $this->email = $contact['email']; - $this->address = $contact['address']; - $this->address_2 = $contact['address_2']; - $this->postal_code = $contact['postal_code']; - $this->city = $contact['city']; - $this->country = $contact['country']; - $this->language = $contact['language']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the contact - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the client that this contact is linked to - * - * @return int The ID - */ - public function getClientId() { - return $this->clientId; - } - - /** - * Get the client that this contact is linked to - * - * @return client The client - */ - public function getClient() { - return new client($this->pdo, $this->clientId); - } - - /** - * Get the name of the contact - * - * @return string The name - */ - public function getName() { - return $this->name; - } - - /** - * Set the name of the contact - * - * @param string $name The new name for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setName($name) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `name`=? WHERE `id`=?"); - $stmt->execute(array($name, $this->id)); - if ($stmt->rowCount() == 1) { - $this->name = $name; - return true; - } else { - return false; - } - } - - /** - * Get the email of the contact - * - * @return string The email - */ - public function getEmail() { - return $this->email; - } - - /** - * Set the email of the contact - * - * @param string $email The new email for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setEmail($email) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `email`=? WHERE `id`=?"); - $stmt->execute(array($email, $this->id)); - if ($stmt->rowCount() == 1) { - $this->email = $email; - return true; - } else { - return false; - } - } - - /** - * Get the first address line of the contact - * - * @return string The address - */ - public function getAddress() { - return $this->address; - } - - /** - * Set the first address line of the contact - * - * @param string $address The new address for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setAddress($address) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address`=? WHERE `id`=?"); - $stmt->execute(array($address, $this->id)); - if ($stmt->rowCount() == 1) { - $this->address = $address; - return true; - } else { - return false; - } - } - - /** - * Get the second address line of the contact - * - * @return string The address - */ - public function getAddress_2() { - return $this->address_2; - } - - /** - * Set the second address line of the contact - * - * @param string $address_2 The new address for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setAddress_2($address_2) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `address_2`=? WHERE `id`=?"); - $stmt->execute(array($address_2, $this->id)); - if ($stmt->rowCount() == 1) { - $this->address_2 = $address_2; - return true; - } else { - return false; - } - } - - /** - * Get the postal_code of the contact - * - * @return string The postal_code - */ - public function getPostalCode() { - return $this->postal_code; - } - - /** - * Set the postal code of the contact - * - * @param $postal_code string The new postal code for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPostalCode($postal_code) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `postal_code`=? WHERE `id`=?"); - $stmt->execute(array($postal_code, $this->id)); - if ($stmt->rowCount() == 1) { - return true; - $this->postal_code = $postal_code; - } else { - return false; - } - } - - /** - * Get the city of the contact - * - * @return string The city - */ - public function getCity() { - return $this->city; - } - - /** - * Set the city of the contact - * - * @param string $city The new city for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setCity($city) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `city`=? WHERE `id`=?"); - $stmt->execute(array($city, $this->id)); - if ($stmt->rowCount() == 1) { - $this->city = $city; - return true; - } else { - return false; - } - } - - /** - * Get the country of the contact - * - * @return string The country - */ - public function getCountry() { - return $this->country; - } - - /** - * Set the country of the contact - * - * @param string $country The new country for the contact - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setCountry($country) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `country`=? WHERE `id`=?"); - $stmt->execute(array($country, $this->id)); - if ($stmt->rowCount() == 1) { - $this->country = $country; - return true; - } else { - return false; - } - } - - /** - * Get the language of the contact - * - * @return string The language - */ - public function getLanguage() { - return $this->language; - } - - /** - * Set the language of the contact - * - * @see correspondence::LANGUAGES The available languages - * - * @param string $language The new language for the contact - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the language is unknown - * - * @return bool True on succes, false on failure - */ - public function setLanguage($language) { - if (!in_array($language, correspondence::LANGUAGES)) { - throw new Exception("Language $language not available."); - } - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."contact` SET `language`=? WHERE `id`=?"); - $stmt->execute(array($language, $this->id)); - if ($stmt->rowCount() == 1) { - $this->language = $language; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Remove this contact from the database - * - * If this doesn't succeed (i.e. false is returned), that means the contact was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."contact` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } - - /** - * Make a new offer for this contact - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return offer A new instance of the offer class containing the new offer - */ - public function createOffer() { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."offer` (`contactId`) VALUES (?)"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() == 1) { - return new offer($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } -} diff --git a/classes/correspondence.php b/classes/correspondence.php deleted file mode 100644 index eb18b7d..0000000 --- a/classes/correspondence.php +++ /dev/null @@ -1,317 +0,0 @@ -. - */ - -/** - * An extension of FPDF to generate personalized correspondence PDFs - */ -class correspondence extends FPDF { - /** - * @var $contact Holds the contact this correspondence will be sent to - * @var $language Holds the language this correspondence should be sent in - */ - var $contact, $language; - - /** - * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs - */ - const HEAD_RED = 0; - const HEAD_GREEN = 0; - const HEAD_BLUE = 0; - - /** - * Available languages - * - * @see _() Translation function - * @see $translations Translations table - */ - const LANGUAGES = ['en', 'nl']; - - /** - * Array holding the translations - * - * @see _() A function to translate - */ - protected static $translations = array( - 'adres' => array( - 'en' => 'Address', - 'nl' => 'Adres'), - 'amount' => array( - 'en' => 'Amount', - 'nl' => 'Subtotaal'), - 'amount-due' => array( - 'en' => 'Total amount due', - 'nl' => 'Te voldoen'), - 'biccode' => array( - 'en' => 'The BIC code of our bank is %%.', - 'nl' => 'De BIC-code van de bank is %%.'), - 'btwnr' => array( - 'en' => 'VAT nr', - 'nl' => 'BTW nr'), - 'description' => array( - 'en' => 'Description', - 'nl' => 'Omschrijving'), - 'due-date' => array( - 'en' => 'Due date', - 'nl' => 'Vervaldatum'), - 'email' => array( - 'en' => 'Email', - 'nl' => 'Email'), - 'iban' => array( - 'en' => 'IBAN', - 'nl' => 'IBAN'), - 'invoice' => array( - 'en' => 'Invoice', - 'nl' => 'Factuur'), - 'invoice-date' => array( - 'en' => 'Invoice date', - 'nl' => 'Factuurdatum'), - 'invoice-nr' => array( - 'en' => 'Invoice number', - 'nl' => 'Factuurnummer'), - 'price-excl' => array( - 'en' => 'Price excl.', - 'nl' => 'Prijs excl.'), - 'price-incl' => array( - 'en' => 'Price incl.', - 'nl' => 'Prijs incl.'), - 'request' => array( - 'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.', - 'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'), - 'tel-nr' => array( - 'en' => 'Tel.', - 'nl' => 'Tel.'), - 'total' => array( - 'en' => 'Total', - 'nl' => 'Totaal'), - 'vat' => array( - 'en' => 'VAT', - 'nl' => 'BTW'), - ); - - /** @var $page_height The height of a page in millimeters */ - protected static $page_height = 297; // A4 - /** @var $margin_bottom The bottom margin in millimeters */ - protected static $margin_bottom = 30; - - /** - * Translate a string - * - * @see $translations The array holding the translations - * - * @param string $key The string to translate - * @param string $lang The language to translate to (two-letter code) - * - * @return string The translated string - */ - public function _($key) { - if (!array_key_exists($key, self::$translations)) - return $key; - return self::$translations[$key][$this->language]; - } - - /** - * Create a new PDF - * - * @param string $orientation See the FPDF class specs - * @param string $unit See the FPDF class specs - * @param string $size See the FPDF class specs - */ - function __construct() { - $this->FPDF('P','mm','A4'); - - $this->SetMargins(30,20,20); - $this->SetAuthor(constants::invoice_name); - $this->SetCreator('BusinessAdmin Correspondence Generator'); - $this->SetDisplayMode('fullpage','continuous'); - } - - /** - * Workaround for euro signs - * - * Euro signs in FPDF should be chr(128). Other signs don't have to be changed. - * - * @return a valuta symbol that can be used in FPDF - */ - public static function valuta() { - switch (constants::invoice_valuta) { - case '€': - return chr(128); - default: - return constants::invoice_valuta; - } - } - - /** - * Set the language of the correspondence (used to translate stuff) - * - * @param string $lang The language, two letter code ('en', 'nl', ...) - */ - function SetLangauge($lang) { - $supported = array('nl', 'en'); - if (!in_array($lang, $supported)) { - throw new Exception("Language not supported"); - } else { - $this->language = $lang; - } - } - - /** - * Set the contact to whom this correspondence will be sent (used for the address) - * - * @param contact $contact The contact - */ - function SetContact($contact) { - $this->contact = $contact; - - $this->language = $contact->getLanguage(); - } - - /** - * Makes a header with your details and the address of the contact - */ - function CorrespondenceHeader() { - if (file_exists(constants::files_folder . 'logo-correspondence.png')) { - $this->Image(constants::files_folder . 'logo-correspondence.png',30,20,50); - } - - $this->SetFont('Helvetica','',7); - $this->Cell(110,20); - $this->Cell(12,1,' ','T'); - $this->Cell(2,1); - $this->Cell(35,1,' ','T'); - $this->Ln(); - - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5,$this->_('adres'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_name); - $this->Ln(); - - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_1); - $this->Ln(); - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_2); - $this->Ln(); - $this->Cell(124,3.5); - $this->Cell(35,3.5, constants::invoice_address_3); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5,$this->_('btwnr'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_tax_nr); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('iban'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_iban); - $this->Ln(); - $this->Cell(160,1.5); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('','',7); - $this->Cell(35,3.5, constants::invoice_tel_nr); - $this->Ln(); - $this->Cell(110,3.5); - $this->SetFont('','B'); - $this->Cell(12,3.5, $this->_('email'),'',0,'R'); - $this->Cell(2,3.5); - $this->SetFont('',''); - $this->Cell(35,3.5, constants::invoice_email); - $this->Ln(); - $this->Cell(110,1); - $this->Cell(12,1,' ','B'); - $this->Cell(2,1); - $this->Cell(35,1,' ','B'); - $this->Ln(); - $this->Cell(160,15); - $this->Ln(); - - $this->SetFont('','',11); - $this->SetXY(30,56.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getName())); - $this->Ln(); - $this->SetXY(30,61.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getAddress())); - $this->Ln(); - $this->SetXY(30,66.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getPostalCode().' '.$this->contact->getCity())); - $this->Ln(); - $this->SetXY(30,71.5); - $this->Cell(90,5.5,utf8_decode($this->contact->getCountry())); - $this->Ln(); - } - - /** - * Put PDF information - */ - function _putinfo() - { - $this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator')); - if(!empty($this->title)) - $this->_out('/Title '.$this->_textstring($this->title)); - if(!empty($this->subject)) - $this->_out('/Subject '.$this->_textstring($this->subject)); - if(!empty($this->author)) - $this->_out('/Author '.$this->_textstring($this->author)); - if(!empty($this->keywords)) - $this->_out('/Keywords '.$this->_textstring($this->keywords)); - if(!empty($this->creator)) - $this->_out('/Creator '.$this->_textstring($this->creator)); - $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); - } - - /** - * Have we reached the bottom of the page yet? - * - * @return bool - */ - public function endOfPage() { - return ($this->GetY() > self::$page_height - self::$margin_bottom); - } - - /** - * Start a new page if we're on the end - */ - public function addPageIfOnEnd() { - if ($this->endOfPage()) { - $this->Ln(); - $this->AddPage(); - $this->Cell(100, 5, ''); // blank line - $this->Ln(); - } - } -} diff --git a/classes/discount.php b/classes/discount.php deleted file mode 100644 index 31be887..0000000 --- a/classes/discount.php +++ /dev/null @@ -1,256 +0,0 @@ -. - */ - -/** - * An interface to the discount table in the database - */ -class discount { - use Calculatable; - - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the discount - * @var int $offerId The id of the offer this discount is linked to - * @var string $title The title of the discount - * @var string $description The description of the discount - * @var float $value The actual discount - * @var float $vat The percentage of VAT to calculate on this discount - */ - protected $pdo, $offerId, $id, $title, $description, $value, $vat; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the discount to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the discount could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."discount` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The discount with id '$id' could not be found."); - } - $discount = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $discount['id']; - $this->offerId = $discount['offerId']; - $this->title = $discount['title']; - $this->description = $discount['description']; - $this->value = $discount['value']; - $this->vat = $discount['VAT_percentage']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the discount - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the offer that this discount is linked to - * - * @return int The ID - */ - public function getOfferId() { - return $this->offerId; - } - - /** - * Get the offer that this discount is linked to - * - * @return offer The offer - */ - public function getOffer() { - return new offer($this->pdo, $this->offerId); - } - - /** - * Get the title of the discount - * - * @return string The title - */ - public function getTitle() { - return $this->title; - } - - /** - * Set the title of the discount - * - * @param string $title The new title for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setTitle($title) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `title`=? WHERE `id`=?"); - $stmt->execute(array($title, $this->id)); - if ($stmt->rowCount() == 1) { - $this->title = $title; - return true; - } else { - return false; - } - } - - /** - * Get the description of the discount - * - * @param bool $parseMarkdown Whether or not to parse markdown - * - * @return string The description - */ - public function getDescription($parseMarkdown = true) { - if ($parseMarkdown) { - $pd = new Parsedown; - return $pd->text($this->description); - } else { - return $this->description; - } - } - - /** - * Set the description of the discount - * - * @param string $description The new description for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setDescription($description) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `description`=? WHERE `id`=?"); - $stmt->execute(array($description, $this->id)); - if ($stmt->rowCount() == 1) { - $this->description = $description; - return true; - } else { - return false; - } - } - - /** - * Get the value of the discount - * - * @return float The value - */ - public function getValue() { - return $this->value; - } - - /** - * Set the value of the discount - * - * @param float $value The new value for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setValue($value) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `value`=? WHERE `id`=?"); - $stmt->execute(array($value, $this->id)); - if ($stmt->rowCount() == 1) { - $this->value = $value; - return true; - } else { - return false; - } - } - - /** - * Get the VAT percentage of the discount - * - * @return float The VAT percentage - */ - public function getVAT() { - return $this->vat; - } - - /** - * Set the VAT percentage of the discount - * - * @param float $vat The new VAT percentage for the discount - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setVAT($vat) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."discount` SET `VAT_percentage`=? WHERE `id`=?"); - $stmt->execute(array($vat, $this->id)); - if ($stmt->rowCount() == 1) { - $this->vat = $vat; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - protected function calculateSubtotal() { - return - $this->value; - } - - protected function calculateVAT() { - return $this->calculateSubtotal() * $this->getVAT() / 100; - } - - /** - * Remove this discount from the database - * - * If this doesn't succeed (i.e. false is returned), that means the discount was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."discount` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} diff --git a/classes/file.php b/classes/file.php deleted file mode 100644 index b07064e..0000000 --- a/classes/file.php +++ /dev/null @@ -1,148 +0,0 @@ -. - */ - -/** - * An interface to the file table in the database - */ -class file { - /** - * @var PDO $pdo The PDO class for database communication - * @var int $id The id of the file - * @var string $filename The relative path to the file - */ - protected $pdo, $id, $filename; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the file to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the file could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."file` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The file with id '$id' could not be found."); - } - $file = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $file['id']; - $this->filename = $file['filename']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the file - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the relative filename of the file - * - * @see file::getFilenamePath To get the full internal path to the file - * @see file::getFilenameURI To get the full external path to the file - * - * @return string The filename - */ - public function getFilename() { - return $this->filename; - } - - /** - * Get the full internal path to the file - * - * @see file::getFilename To get the relative filename - * @see file::getFilenameURI To get the full external path to the file - * - * @return string The path - */ - public function getFilenamePath() { - return constants::files_folder . $this->filename; - } - - /** - * Get the full external path to the file - * - * @see file::getFilename To get the relative filename - * @see file::getFilenamePath To get the full internal path to the file - * - * @return string The URI - */ - public function getFilenameURI() { - return constants::files_folder_external . $this->filename; - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Move this file to the trash and delete all records for it - * - * Physically, this moves the file to a trash folder - * Then, the file will be removed from the file table in the database - * Any appendices linking to this file with fileId will have fileId NULL - * Any offers linking to this file with invoice_fileId will have invoice_fileId NULL - * - * @throws PDOException If there's something wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - // Try to move the file to trash - $newname = pathinfo($this->filename, PATHINFO_FILENAME) . '--' . date('Y-m-d.H.i.s.') . pathinfo($this->filename, PATHINFO_EXTENSION); - $newdir = pathinfo($this->getFilenamePath(), PATHINFO_DIRNAME) . '/' . constants::files_folder_trash . '/'; - if (!file_exists($newdir)) { - if (!mkdir($newdir)) { - return false; - } - } - if (!(@rename($this->getFilenamePath(), $newdir . $newname))) { - return false; - } - - // Remove offers linked by invoice_fileId - $this->pdo->query("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=NULL WHERE `invoice_fileId`={$this->id}"); - - // Remove the record of the file - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."file` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() == 1) { - return true; - } else { - return false; - } - } -} diff --git a/classes/fpdf.license.txt b/classes/fpdf.license.txt deleted file mode 100644 index fd811c6..0000000 --- a/classes/fpdf.license.txt +++ /dev/null @@ -1,6 +0,0 @@ -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software to use, copy, modify, distribute, sublicense, and/or sell -copies of the software, and to permit persons to whom the software is furnished -to do so. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. \ No newline at end of file diff --git a/classes/offer.php b/classes/offer.php deleted file mode 100644 index 56a8878..0000000 --- a/classes/offer.php +++ /dev/null @@ -1,747 +0,0 @@ -. - */ - -/** - * An interface to the offer table in the database - */ -class offer { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the offer - * @var int $contactId The id of the contact this offer is linked to - * @var int $start_date A UNIX timestamp of the start date - * @var int $end_date A UNIX timestamp of the end date - * @var int $invoice_date A UNIX timestamp of the invoice date - * @var bool $accepted Whether the offer is accepted or not - * @var null|int $invoice_fileId If an invoice has been generated, an the id of the file - */ - protected $pdo, $id, $contactId, $start_date, $end_date, $invoice_date, $accepted, $invoice_fileId; - - const SUBTOTAL = 1; - const VAT = 2; - const TOTAL = 3; - - /** - * Create a new instance - * - * Blah - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the offer to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the offer could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."offer` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The offer with id '$id' could not be found."); - } - $offer = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $offer['id']; - $this->contactId = $offer['contactId']; - $this->start_date = strtotime($offer['start_date']); - $this->end_date = strtotime($offer['end_date']); - $this->invoice_date = strtotime($offer['invoice_date']); - $this->accepted = (bool) $offer['accepted']; - $this->invoice_fileId = $offer['invoice_fileId']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the offer - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the contact that this offer is linked to - * - * @see offer::getContact() This function returns the contact as an instance of the object class - * - * @return int The ID - */ - public function getContactId() { - return $this->contactId; - } - - /** - * Get the contact that this offer is linked to - * - * @see offer::getContactId() This function returns just the id - * - * @return contact The contact - */ - public function getContact() { - return new contact($this->pdo, $this->contactId); - } - - /** - * Get all assignment ids for this offer - * - * @see offer::getAssignments() This funtion returns instances of the assignment class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getAssignmentIds() { - $ids = array(); - $assignments = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."assignment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($assignments as $assignment) { - $ids[] = $assignment['id']; - } - return $ids; - } - - /** - * Get all assignments for this offer - * - * @see offer::getAssignmentIds() This function returns just the ids of the assignments, and not instances of the assignment class - * - * @throws PDOException If something went wrong with the database - * - * @return assignment[] An array indexed by id of instances of the assignment class - */ - public function getAssignments() { - $ids = $this->getAssignmentIds(); - $assignments = array(); - foreach ($ids as $id) { - $assignments[$id] = new assignment($this->pdo, $id); - } - return $assignments; - } - - /** - * Get all discount ids for this offer - * - * @see offer::getDiscounts() This funtion returns instances of the discount class instead of just the ids - * - * @throws PDOException Is something went wrong with the database - * - * @return int[] The ids - */ - public function getDiscountIds() { - $ids = array(); - $discounts = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."discount` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($discounts as $discount) { - $ids[] = $discount['id']; - } - return $ids; - } - - /** - * Get all discounts for this offer - * - * @see offer::getDiscountIds() This function returns just the ids of the discounts, and not instances of the discount class - * - * @throws PDOException If something went wrong with the database - * - * @return discount[] An array indexed by id of instances of the discount class - */ - public function getDiscounts() { - $ids = $this->getDiscountIds(); - $discounts = array(); - foreach ($ids as $id) { - $discounts[$id] = new discount($this->pdo, $id); - } - return $discounts; - } - - /** - * Get the payment id for this offer - * - * @see offer::getPayment() This funtion returns an instance of the payment class instead of just the id - * - * @throws PDOException Is something went wrong with the database - * - * @return int|null The id, or null if no payment exists - */ - public function getPaymentId() { - $ids = array(); - $payments = $this->pdo->query("SELECT `id` FROM `".constants::db_prefix."payment` WHERE `offerId`={$this->id}")->fetchAll(PDO::FETCH_ASSOC); - foreach ($payments as $payment) { - return $payment['id']; - } - return null; - } - - /** - * Get the payment for this offer - * - * @see offer::getPaymentId() This function returns just the id of the payment, and not an instance of the payment class - * - * @throws PDOException If something went wrong with the database - * - * @return payment|null The payment, or null if it does not exist - */ - public function getPayment() { - $id = $this->getPaymentId(); - if (is_null($id)) { - return null; - } else { - return new payment($this->pdo, $id); - } - } - - /** - * Get the start date of the assignment - * - * @return int The start date as a UNIX timestamp - */ - public function getStartDate() { - return $this->start_date; - } - - /** - * Set the start date of the assignment - * - * @param int $start_date The new start date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setStartDate($start_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `start_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $start_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->start_date = $start_date; - return true; - } else { - return false; - } - } - - /** - * Get the end date of the assignment - * - * @return int The end date as a UNIX timestamp - */ - public function getEndDate() { - return $this->end_date; - } - - /** - * Set the end date of the assignment - * - * @param int $end_date The new end date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setEndDate($end_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `end_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $end_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->end_date = $end_date; - return true; - } else { - return false; - } - } - - /** - * Get the invoice date of the assignment - * - * @return int The invoice date as a UNIX timestamp - */ - public function getInvoiceDate() { - return $this->invoice_date; - } - - /** - * Set the invoice date of the assignment - * - * @param int $invoice_date The new invoice date for the assignment as a UNIX timestamp - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setInvoiceDate($invoice_date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_date`=? WHERE `id`=?"); - $stmt->execute(array(date('Y-m-d', $invoice_date), $this->id)); - if ($stmt->rowCount() == 1) { - $this->invoice_date = $invoice_date; - return true; - } else { - return false; - } - } - - /** - * Get the date the payment was received - * - * @return int|null The date as a UNIX timestamp, or null if it wasn't received yet - */ - public function getPaymentReceived() { - $payment = $this->getPayment(); - if (is_null($payment)) { - return null; - } else { - return $payment->getDate(); - } - } - - /** - * Check if the offer is accepted or not - * - * @return bool True if the offer is accepted, false if not - */ - public function isAccepted() { - return $this->accepted; - } - - /** - * Toggle the `accepted' status of the offer - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function toggleAccepted() { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `accepted`=? WHERE `id`=?"); - $new_value = !$this->accepted; - $stmt->execute(array($new_value, $this->id)); - if ($stmt->rowCount() == 1) { - $this->accepted = $new_value; - return true; - } else { - return false; - } - } - - /** - * Get the ID of the file that the invoice of this offer is linked to - * - * @see offer::getInvoiceFile() This function returns the file as an instance of the file class - * - * @return int The ID - */ - public function getInvoiceFileId() { - return $this->invoice_fileId; - } - - /** - * Get the file that the invoice this offer is linked to - * - * @see offer::getInvoiceId() This function returns just the id - * - * @return file|null The file, or null if it doesn't exist - */ - public function getInvoiceFile() { - if ($this->invoice_fileId != null) { - return new file($this->pdo, $this->invoice_fileId); - } else { - return null; - } - } - - /** - * Set the invoice file id of the assignment - * - * @param int $invoice_fileId The new invoice file id for the assignment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setInvoiceFileId($invoice_fileId) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."offer` SET `invoice_fileId`=? WHERE `id`=?"); - $stmt->execute(array($invoice_fileId, $this->id)); - if ($stmt->rowCount() == 1) { - $this->invoice_fileId = $invoice_fileId; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Calculate a handy number about the invoice - * - * Subtotal: the sum of the prices of the assignments excl. VAT - * - * VAT: the sum of all the VAT from all the assignments - * - * Total: the sum of subtotal and total - * - * @param int $what Any of offer::SUBTOTAL, offer::VAT and offer::TOTAL - * @param int $round How many decimals to round the result on - * @param bool $format Whether to format the number nicely (for output) or not (for calculations) - * - * @throws PDOException If something went wrong with the database - * - * @return float|bool The calculated value rounded to $round decimals, or false on incorrect input - */ - public function calculate($what = self::TOTAL, $round = 2, $format = true) { - $return = 0; - switch ($what) { - case self::SUBTOTAL: - foreach ($this->getAssignments() as $assignment) { - $return += $assignment->calculate(assignment::SUBTOTAL, $round + 1, false); - } - foreach ($this->getDiscounts() as $discount) { - $return += $discount->calculate(discount::SUBTOTAL, $round + 1, false); - } - break; - case self::VAT: - $assignments = $this->getAssignments(); - foreach ($assignments as $assignment) { - $return += $assignment->calculate(assignment::VAT, $round + 1, false); - } - foreach ($this->getDiscounts() as $discount) { - $return += $discount->calculate(discount::VAT, $round + 1, false); - } - break; - case self::TOTAL: - $return = $this->calculate(self::SUBTOTAL, $round + 1, false) + $this->calculate(self::VAT, $round + 1, false); - break; - default: - return false; - } - if ($format) { - return number_format($return, 2); - } else { - return round($return, 2); - } - } - - /** - * Remove this offer from the database - * - * If this doesn't succeed (i.e. false is returned), that means the offer was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."offer` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } - - /** - * Make a new assignment linked to this order - * - * @param string $title The title for this assignment - * @param string $description The description for this assignment - * @param int $hours The amount of hours to work on this assignment - * @param float $price_per_hour The price per hour on this assignment - * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return assignment A new instance of the assignment class containing the new assignment - */ - public function createAssignment($title, $description, $hours, $price_per_hour, $vat) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."assignment` (`offerId`,`title`,`description`,`hours`,`price_per_hour`,`VAT_percentage`) VALUES (?,?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $title, - $description, - $hours, - $price_per_hour, - $vat - )); - if ($stmt->rowCount() == 1) { - return new assignment($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } - - /** - * Make a new discount linked to this order - * - * @param string $title The title for this discount - * @param string $description The description for this discount - * @param float $value The value for this discount - * @param float $vat The VAT percentage (so, 21 for 21%, not 0.21!) - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return discount A new instance of the discount class containing the new discount - */ - public function createDiscount($title, $description, $value, $vat) { - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."discount` (`offerId`,`title`,`description`,`value`,`VAT_percentage`) VALUES (?,?,?,?,?)"); - $stmt->execute(array( - $this->id, - $title, - $description, - $value, - $vat - )); - if ($stmt->rowCount() == 1) { - return new discount($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } - - /** - * Add a payment for this order - * - * @param string $date Optional: the date for the payment - * - * @throws PDOException If something went wrong with the database - * @throws Exception If there was a problem with the input - * - * @return payment A new instance of the payment class containing the new payment - */ - public function createPayment($date=null) { - $date = is_null($date) ? time() : $date; - $stmt = $this->pdo->prepare("INSERT INTO `".constants::db_prefix."payment` (`offerId`,`date`) VALUES (?,?)"); - $stmt->execute([$this->id, date('Y-m-d H:i:s', $date)]); - if ($stmt->rowCount() == 1) { - return new payment($this->pdo, $this->pdo->lastInsertId()); - } else { - $error = $stmt->errorInfo(); - throw new Exception($error[2]); - } - } - - /** - * Generate a PDF invoice - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the file could not be written or an other error occured - * - * @return file An instance of the file class with information on the invoice file generated - */ - public function generateInvoice() { - // Check if we already have a file - $file = $this->getInvoiceFile(); - if (!($file instanceof file)) { - // If not, create a new file - $i = 1; - do { - $invoice_nr = date('Y',$this->invoice_date) . str_pad($i++, 2, '0', STR_PAD_LEFT); - $filename = 'invoice-' . $invoice_nr . '.pdf'; - } while (file_exists(constants::files_folder . $filename)); - $file = BusinessAdmin::createFile($this->pdo, $filename); - - $this->setInvoiceFileId($file->getId()); - } else { - $invoice_nr = str_replace(array('invoice-','.pdf'), array('',''), $file->getFilename()); - } - - $list = array(); - foreach ($this->getAssignments() as $assignment) - $list[] = array( - $assignment->getTitle(), - $assignment->getPricePerHour() * $assignment->getHours(), - $assignment->getVAT() . "%", - $assignment->getPricePerHour() * $assignment->getHours() * (1 + $assignment->getVAT() / 100) - ); - foreach ($this->getDiscounts() as $discount) - $list[] = array( - $discount->getTitle(), - $discount->calculate(discount::SUBTOTAL), - $discount->getVAT() . "%", - $discount->calculate(discount::TOTAL) - ); - - $pdf = new correspondence(); - $pdf->SetContact($this->getContact()); - $pdf->SetTitle($pdf->_('invoice') . ' ' . $invoice_nr); - $pdf->AddPage(); - $pdf->correspondenceHeader(); - - $pdf->SetY(100); - $pdf->SetFont('','B',14); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->Cell(60,6, $pdf->_('invoice'),'B'); - $pdf->SetTextColor(0); - $pdf->Ln(); - - $width = array(90,25,20,25); - $subtotal = 0; - $btw = array(); - $total = 0; - - // Header - - $pdf->SetFont('','',9); - $pdf->Cell(60,4); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('invoice-date')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,date("d-m-Y", $this->invoice_date)); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('invoice-nr')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,$invoice_nr); - $pdf->Ln(); - $pdf->SetFont('','B'); - $pdf->Cell(30,4.5,$pdf->_('due-date')); - $pdf->SetFont('',''); - $pdf->Cell(50,4.5,date("d-m-Y",$this->invoice_date+3600*24*30)); - $pdf->Ln(); - $pdf->Cell(60,4.5,'','B'); - $pdf->Ln(); - - $pdf->SetY(140); - - // Table - - $pdf->SetFont('','B',11); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->Cell($width[0],7,$pdf->_('description'),'B'); - $pdf->Cell($width[1],7,$pdf->_('price-excl'),'B',0,'R'); - $pdf->Cell($width[2],7,$pdf->_('vat'),'B',0,'R'); - $pdf->Cell($width[3],7,$pdf->_('price-incl'),'B',0,'R'); - $pdf->SetTextColor(0); - $pdf->Ln(); - - $pdf->SetFont('',''); - foreach ($list as $row) { - $x = $pdf->getX(); - $y = $pdf->getY(); - $pdf->MultiCell($width[0],6,iconv('utf-8', 'iso-8859-1', $row[0]),0,'L'); - $newy = $pdf->getY(); - $pdf->SetXY($x + $width[0], $y); - $pdf->Cell($width[1],6,correspondence::valuta().number_format($row[1],2),'',0,'R'); - $pdf->Cell($width[2],6,round($row[2],0) . '%','',0,'R'); - $pdf->Cell($width[3],6,correspondence::valuta().number_format($row[3],2),'',0,'R'); - $pdf->Ln(); - $pdf->SetY($newy); - $pdf->addPageIfOnEnd(); - $subtotal += $row[1]; - if (!isset($btw[$row[2]])) $btw[$row[2]] = 0; - $btw[$row[2]] += $row[3] - $row[1]; - } - $total = $subtotal; - foreach ($btw as $m) { - $total += $m; - } - - $pdf->Cell(array_sum($width),5,'','T'); - $pdf->Ln(); - $pdf->Cell(array_sum($width),5); - $pdf->Ln(); - - $pdf->Cell($width[0],7); - $pdf->SetFont('','B'); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('amount')); - $pdf->SetFont('',''); - $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::SUBTOTAL),'',0,'R'); - $pdf->Ln(); - - foreach ($btw as $p => $m) { - $pdf->Cell($width[0],7); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('vat') . ' '.round($p,0).'%'); - $pdf->Cell($width[3],7,correspondence::valuta() . number_format($m,2),'',0,'R'); - $pdf->Ln(); - } - - $pdf->Cell(array_sum($width),5); - $pdf->Ln(); - - $pdf->Cell($width[0],7); - $pdf->SetFont('','B'); - $pdf->Cell($width[1] + $width[2],7,$pdf->_('total')); - $pdf->SetFont('',''); - $pdf->Cell($width[3],7,correspondence::valuta() . $this->calculate(self::TOTAL),'T',0,'R'); - $pdf->Ln(); - - // Footer - - $pdf->Ln(); - $pdf->addPageIfOnEnd(); - if ($pdf->GetY() < 230) { - $pdf->SetY(230); - } - $oldY = $pdf->GetY(); - $pdf->Cell(45,20,'',1); - $pdf->Cell(12.5,20); - $pdf->Cell(45,20,'',1); - $pdf->Cell(12.5,20); - $pdf->Cell(45,20,'',1); - - $pdf->SetFont('','B',10); - $pdf->SetTextColor(correspondence::HEAD_RED, correspondence::HEAD_GREEN, correspondence::HEAD_BLUE); - $pdf->SetY($oldY + 3); - $pdf->Cell(5,5); - $pdf->Cell(40,5,$pdf->_('iban')); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$pdf->_('invoice-nr')); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$pdf->_('amount-due')); - $pdf->SetTextColor(0); - - $pdf->SetFont('','',8); - $pdf->Ln(); - $pdf->Ln(); - $oldY = $pdf->GetY(); - - $pdf->Cell(5,5); - $pdf->Cell(40,5, constants::invoice_iban); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,$invoice_nr); - $pdf->Cell(17.5,5); - $pdf->Cell(40,5,correspondence::valuta() . $this->calculate(self::TOTAL)); - - $pdf->SetY($oldY + 14); - - $pdf->SetFontSize(7); - $pdf->Cell(160,5,$pdf->_('request'),0,0,'C'); - $pdf->Ln(); - $pdf->Cell(160,5,str_replace('%%', constants::invoice_bic, $pdf->_('biccode')),0,0,'C'); - - if (file_exists($file->getFilenamePath())) { - unlink($file->getFilenamePath()); - } - $pdf->Output($file->getFilenamePath(),'F'); - chmod($file->getFilenamePath(),0644); - - return $file; - } -} diff --git a/classes/payment.php b/classes/payment.php deleted file mode 100644 index 9d4782c..0000000 --- a/classes/payment.php +++ /dev/null @@ -1,142 +0,0 @@ -. - */ - -/** - * An interface to the payment table in the database - */ -class payment { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the payment - * @var int $offerId The id of the offer this payment is linked to - * @var int $date A unix timestamp describing the date of the payment - */ - protected $pdo, $offerId, $id, $date; - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the payment to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the payment could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."payment` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The payment with id '$id' could not be found."); - } - $payment = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $payment['id']; - $this->offerId = $payment['offerId']; - $this->date = strtotime($payment['date']); - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the payment - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the ID of the offer that this payment is linked to - * - * @return int The ID - */ - public function getOfferId() { - return $this->offerId; - } - - /** - * Get the offer that this payment is linked to - * - * @return offer The offer - */ - public function getOffer() { - return new offer($this->pdo, $this->offerId); - } - - /** - * Get the date of the payment - * - * @return int A unix timestamp describing the date of the payment - */ - public function getDate() { - return $this->date; - } - - /** - * Set the date of the payment - * - * @param int $date The new date for the payment - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function setDate($date) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."payment` SET `date`=? WHERE `id`=?"); - $stmt->execute([date('Y-m-d H:i:s', $date), $this->id]); - if ($stmt->rowCount() == 1) { - $this->date = $date; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Remove this payment from the database - * - * If this doesn't succeed (i.e. false is returned), that means the payment was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."payment` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} diff --git a/classes/response.php b/classes/response.php deleted file mode 100644 index d997c00..0000000 --- a/classes/response.php +++ /dev/null @@ -1,112 +0,0 @@ -. - */ - -/** - * Provides a standard to base all responses to be called with AJAX on - */ -class response { - /** The variable to keep the response in until output */ - private $response; - /** The variable to keep the HTTP response code in until output */ - private $http_response_code; - - /** - * Create a new instance - */ - public function __construct() { - $this->response = array(); - $this->http_response_code = 200; - } - - /** - * Set a variable of the response - * - * @param string $name The name of the variable to set - * @param string $value The (new) value for the variable - */ - public function __set($name, $value) { - $this->response[$name] = $value; - } - - /** - * Get a variable of the response - * - * @param string $name The name of the variable to get - * - * @return mixed The value of the variable - */ - public function __get($name) { - return $this->response[$name]; - } - - /** - * Check if a variable of the response is set - * - * @param string $name The name of the variable to check - * - * @return bool True if the variable exists, false otherwise - */ - public function __isset($name) { - return isset($this->response[$name]); - } - - /** - * Unset a variable of the response - * - * @param string $name The variable to unset - */ - public function __unset($name) { - unset($this->response[$name]); - } - - /** - * Get or set the HTTP response code - * - * If a parameter is provided, it is used as the new HTTP response code, and a bool is returned for success or failure. Otherwise, the current one is returned. - * - * @param int $code The new code - * - * @return int|bool True on successful change, false on unsuccesful change, int when the current code is returned - */ - public function http_response_code($code = null) { - if ($code === null) { - return $this->http_response_code; - } else { - if (http_response_code($code)) { - $this->http_response_code = $code; - return true; - } else { - return false; - } - } - } - - /** - * Output the response in json - * - * @return string The response in json format - */ - public function getJson() { - return json_encode($this->response); - } -} diff --git a/classes/user.php b/classes/user.php deleted file mode 100644 index f6c6322..0000000 --- a/classes/user.php +++ /dev/null @@ -1,198 +0,0 @@ -. - */ - -/** - * An interface to the user table in the database - */ -class user { - /** - * @var pdo $pdo The PDO class for database communication - * @var int $id The id of the user - * @var string $username The username of the user - * @var string $password The (hashed) password of the user - */ - protected $pdo, $id, $username, $password; - - /** - * Generate a random password - * - * @return string The password - */ - public static function generateRandomPassword() { - return preg_replace('/[^\w]/', '', - base64_encode(bin2hex(openssl_random_pseudo_bytes(4)))); - } - - /** - * Hash a password - * - * @param string $password The password to be hashed - * @param int $cost The password cost - * - * @return string The hashed password - */ - public static function hash($password, $cost=null) { - return password_hash( - $password, - constants::password_algo, - ['cost' => is_null($cost) ? constants::password_cost : $cost] - ); - } - - /** - * Create a new instance - * - * @param PDO $pdo The PDO class, to access the database - * @param int $id The id of the user to fetch - * - * @throws PDOException If something went wrong with the database - * @throws Exception If the user could not be found - */ - public function __construct($pdo, $id) { - $this->pdo = $pdo; - - $stmt = $this->pdo->prepare("SELECT * FROM `".constants::db_prefix."user` WHERE `id`=?"); - $stmt->execute(array($id)); - if ($stmt->rowCount() == 0) { - throw new Exception("The user with id '$id' could not be found."); - } - $user = $stmt->fetch(PDO::FETCH_ASSOC); - - $this->id = $user['id']; - $this->username = $user['username']; - $this->password = $user['password']; - } - - //------------------------------------------------------------------------------ - // Getters and setters - //------------------------------------------------------------------------------ - - /** - * Get the ID of the user - * - * @return int The ID - */ - public function getId() { - return $this->id; - } - - /** - * Get the username of the user - * - * @return string The username - */ - public function getUsername() { - return $this->username; - } - - /** - * Set the username of the user - * - * @param string $username The new username for the user - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setName($username) { - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."user` SET `username`=? WHERE `id`=?"); - $stmt->execute(array($username, $this->id)); - if ($stmt->rowCount() == 1) { - $this->username = $username; - return true; - } else { - return false; - } - } - - /** - * Set the password of the user - * - * @param string $password The new password for the user - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on succes, false on failure - */ - public function setPassword($password) { - $password = self::hash($password); - $stmt = $this->pdo->prepare("UPDATE `".constants::db_prefix."user` SET `password`=? WHERE `id`=?"); - $stmt->execute(array($password, $this->id)); - if ($stmt->rowCount() == 1) { - $this->password = $password; - return true; - } else { - return false; - } - } - - //------------------------------------------------------------------------------ - // Other functions - //------------------------------------------------------------------------------ - - /** - * Check if a user has administrator rights - * - * @return bool True iff the user has administrator rights - */ - public function isAdmin() { - return in_array($this->getId(), constants::user_admins); - } - - /** - * Verify a password - * - * @param string $password The password to verify - * - * @return bool True iff the password can be accepted - */ - public function verifyPassword($password) { - if (!password_verify($password, $this->password)) { - return false; - } - if (password_needs_rehash($this->password, constants::password_algo, - ['cost' => constants::password_cost])) { - $this->setPassword($password); - } - return true; - } - - /** - * Remove this user from the database - * - * If this doesn't succeed (i.e. false is returned), that means the user was removed manually or by another instance of this class - * - * @throws PDOException If something went wrong with the database - * - * @return bool True on success, false on failure - */ - public function delete() { - $stmt = $this->pdo->prepare("DELETE FROM `".constants::db_prefix."user` WHERE `id`=?"); - $stmt->execute(array($this->id)); - if ($stmt->rowCount() != 1) { - return false; - } else { - return true; - } - } -} -- cgit v1.2.3