diff options
author | Luke Shumaker <LukeShu@sbcglobal.net> | 2011-05-17 16:27:50 -0400 |
---|---|---|
committer | Luke Shumaker <LukeShu@sbcglobal.net> | 2011-05-17 16:27:50 -0400 |
commit | b81536ad49001abf292bd31a0dcbf57e387387b1 (patch) | |
tree | 722cac2e9eab46a3b18d930dcd37703df48ebeba /.emacs.d/org-7.4/contrib/lisp/org-invoice.el | |
parent | 5b8794f1f5e82c1a220f36a724e5c8ce3335c462 (diff) |
Fiddle with emacs config (when to use -n, -c), get emacs using el-get.
Diffstat (limited to '.emacs.d/org-7.4/contrib/lisp/org-invoice.el')
-rw-r--r-- | .emacs.d/org-7.4/contrib/lisp/org-invoice.el | 399 |
1 files changed, 0 insertions, 399 deletions
diff --git a/.emacs.d/org-7.4/contrib/lisp/org-invoice.el b/.emacs.d/org-7.4/contrib/lisp/org-invoice.el deleted file mode 100644 index 7e2dad2..0000000 --- a/.emacs.d/org-7.4/contrib/lisp/org-invoice.el +++ /dev/null @@ -1,399 +0,0 @@ -;;; org-invoice.el --- Help manage client invoices in OrgMode -;; -;; Copyright (C) 2008 pmade inc. (Peter Jones pjones@pmade.com) -;; -;; Permission is hereby granted, free of charge, to any person obtaining -;; a copy of this software and associated documentation files (the -;; "Software"), to deal in the Software without restriction, including -;; without limitation the rights to use, copy, modify, merge, publish, -;; distribute, sublicense, and/or sell copies of the Software, and to -;; permit persons to whom the Software is furnished to do so, subject to -;; the following conditions: -;; -;; The above copyright notice and this permission notice shall be -;; included in all copies or substantial portions of the Software. -;; -;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; -;; Commentary: -;; -;; Building on top of the terrific OrgMode, org-invoice tries to -;; provide functionality for managing invoices. Currently, it does -;; this by implementing an OrgMode dynamic block where invoice -;; information is aggregated so that it can be exported. -;; -;; It also provides a library of functions that can be used to collect -;; this invoice information and use it in other ways, such as -;; submitting it to on-line invoicing tools. -;; -;; I'm already working on an elisp package to submit this invoice data -;; to the FreshBooks on-line accounting tool. -;; -;; Usage: -;; -;; In your ~/.emacs: -;; (autoload 'org-invoice-report "org-invoice") -;; (autoload 'org-dblock-write:invoice "org-invoice") -;; -;; See the documentation in the following functions: -;; -;; `org-invoice-report' -;; `org-dblock-write:invoice' -;; -;; Latest version: -;; -;; git clone git://pmade.com/elisp -(eval-when-compile - (require 'cl) - (require 'org)) - -(defgroup org-invoice nil - "OrgMode Invoice Helper" - :tag "Org-Invoice" :group 'org) - -(defcustom org-invoice-long-date-format "%A, %B %d, %Y" - "The format string for long dates." - :type 'string :group 'org-invoice) - -(defcustom org-invoice-strip-ts t - "Remove org timestamps that appear in headings." - :type 'boolean :group 'org-invoice) - -(defcustom org-invoice-default-level 2 - "The heading level at which a new invoice starts. This value -is used if you don't specify a scope option to the invoice block, -and when other invoice helpers are trying to find the heading -that starts an invoice. - -The default is 2, assuming that you structure your invoices so -that they fall under a single heading like below: - -* Invoices -** This is invoice number 1... -** This is invoice number 2... - -If you don't structure your invoices using those conventions, -change this setting to the number that corresponds to the heading -at which an invoice begins." - :type 'integer :group 'org-invoice) - -(defcustom org-invoice-start-hook nil - "Hook called when org-invoice is about to collect data from an -invoice heading. When this hook is called, point will be on the -heading where the invoice begins. - -When called, `org-invoice-current-invoice' will be set to the -alist that represents the info for this invoice." - :type 'hook :group 'org-invoice) - - (defcustom org-invoice-heading-hook nil - "Hook called when org-invoice is collecting data from a -heading. You can use this hook to add additional information to -the alist that represents the heading. - -When this hook is called, point will be on the current heading -being processed, and `org-invoice-current-item' will contain the -alist for the current heading. - -This hook is called repeatedly for each invoice item processed." - :type 'hook :group 'org-invoice) - -(defvar org-invoice-current-invoice nil - "Information about the current invoice.") - -(defvar org-invoice-current-item nil - "Information about the current invoice item.") - -(defvar org-invoice-table-params nil - "The table parameters currently being used.") - -(defvar org-invoice-total-time nil - "The total invoice time for the summary line.") - -(defvar org-invoice-total-price nil - "The total invoice price for the summary line.") - -(defconst org-invoice-version "1.0.0" - "The org-invoice version number.") - -(defun org-invoice-goto-tree (&optional tree) - "Move point to the heading that represents the head of the -current invoice. The heading level will be taken from -`org-invoice-default-level' unless tree is set to a string that -looks like tree2, where the level is 2." - (let ((level org-invoice-default-level)) - (save-match-data - (when (and tree (string-match "^tree\\([0-9]+\\)$" tree)) - (setq level (string-to-number (match-string 1 tree))))) - (org-back-to-heading) - (while (and (> (org-reduced-level (org-outline-level)) level) - (org-up-heading-safe))))) - -(defun org-invoice-heading-info () - "Return invoice information from the current heading." - (let ((title (org-no-properties (org-get-heading t))) - (date (org-entry-get nil "TIMESTAMP" 'selective)) - (work (org-entry-get nil "WORK" nil)) - (rate (or (org-entry-get nil "RATE" t) "0")) - (level (org-outline-level)) - raw-date long-date) - (unless date (setq date (org-entry-get nil "TIMESTAMP_IA" 'selective))) - (unless date (setq date (org-entry-get nil "TIMESTAMP" t))) - (unless date (setq date (org-entry-get nil "TIMESTAMP_IA" t))) - (unless work (setq work (org-entry-get nil "CLOCKSUM" nil))) - (unless work (setq work "00:00")) - (when date - (setq raw-date (apply 'encode-time (org-parse-time-string date))) - (setq long-date (format-time-string org-invoice-long-date-format raw-date))) - (when (and org-invoice-strip-ts (string-match org-ts-regexp-both title)) - (setq title (replace-match "" nil nil title))) - (when (string-match "^[ \t]+" title) - (setq title (replace-match "" nil nil title))) - (when (string-match "[ \t]+$" title) - (setq title (replace-match "" nil nil title))) - (setq work (org-hh:mm-string-to-minutes work)) - (setq rate (string-to-number rate)) - (setq org-invoice-current-item (list (cons 'title title) - (cons 'date date) - (cons 'raw-date raw-date) - (cons 'long-date long-date) - (cons 'work work) - (cons 'rate rate) - (cons 'level level) - (cons 'price (* rate (/ work 60.0))))) - (run-hook-with-args 'org-invoice-heading-hook) - org-invoice-current-item)) - -(defun org-invoice-level-min-max (ls) - "Return a list where the car is the min level, and the cdr the max." - (let ((max 0) min level) - (dolist (info ls) - (when (cdr (assoc 'date info)) - (setq level (cdr (assoc 'level info))) - (when (or (not min) (< level min)) (setq min level)) - (when (> level max) (setq max level)))) - (cons (or min 0) max))) - -(defun org-invoice-collapse-list (ls) - "Reorganize the given list by dates." - (let ((min-max (org-invoice-level-min-max ls)) new) - (dolist (info ls) - (let* ((date (cdr (assoc 'date info))) - (work (cdr (assoc 'work info))) - (price (cdr (assoc 'price info))) - (long-date (cdr (assoc 'long-date info))) - (level (cdr (assoc 'level info))) - (bucket (cdr (assoc date new)))) - (if (and (/= (car min-max) (cdr min-max)) - (= (car min-max) level) - (= work 0) (not bucket) date) - (progn - (setq info (assq-delete-all 'work info)) - (push (cons 'total-work 0) info) - (push (cons date (list info)) new) - (setq bucket (cdr (assoc date new)))) - (when (and date (not bucket)) - (setq bucket (list (list (cons 'date date) - (cons 'title long-date) - (cons 'total-work 0) - (cons 'price 0)))) - (push (cons date bucket) new) - (setq bucket (cdr (assoc date new)))) - (when (and date bucket) - (setcdr (assoc 'total-work (car bucket)) - (+ work (cdr (assoc 'total-work (car bucket))))) - (setcdr (assoc 'price (car bucket)) - (+ price (cdr (assoc 'price (car bucket))))) - (nconc bucket (list info)))))) - (nreverse new))) - -(defun org-invoice-info-to-table (info) - "Create a single org table row from the given info alist." - (let ((title (cdr (assoc 'title info))) - (total (cdr (assoc 'total-work info))) - (work (cdr (assoc 'work info))) - (price (cdr (assoc 'price info))) - (with-price (plist-get org-invoice-table-params :price))) - (unless total - (setq - org-invoice-total-time (+ org-invoice-total-time work) - org-invoice-total-price (+ org-invoice-total-price price))) - (setq total (and total (org-minutes-to-hh:mm-string total))) - (setq work (and work (org-minutes-to-hh:mm-string work))) - (insert-before-markers - (concat "|" title - (cond - (total (concat "|" total)) - (work (concat "|" work))) - (and with-price price (concat "|" (format "%.2f" price))) - "|" "\n")))) - -(defun org-invoice-list-to-table (ls) - "Convert a list of heading info to an org table" - (let ((with-price (plist-get org-invoice-table-params :price)) - (with-summary (plist-get org-invoice-table-params :summary)) - (with-header (plist-get org-invoice-table-params :headers)) - (org-invoice-total-time 0) - (org-invoice-total-price 0)) - (insert-before-markers - (concat "| Task / Date | Time" (and with-price "| Price") "|\n")) - (dolist (info ls) - (insert-before-markers "|-\n") - (mapc 'org-invoice-info-to-table (if with-header (cdr info) (cdr (cdr info))))) - (when with-summary - (insert-before-markers - (concat "|-\n|Total:|" - (org-minutes-to-hh:mm-string org-invoice-total-time) - (and with-price (concat "|" (format "%.2f" org-invoice-total-price))) - "|\n"))))) - -(defun org-invoice-collect-invoice-data () - "Collect all the invoice data from the current OrgMode tree and -return it. Before you call this function, move point to the -heading that begins the invoice data, usually using the -`org-invoice-goto-tree' function." - (let ((org-invoice-current-invoice - (list (cons 'point (point)) (cons 'buffer (current-buffer)))) - (org-invoice-current-item nil)) - (save-restriction - (org-narrow-to-subtree) - (org-clock-sum) - (run-hook-with-args 'org-invoice-start-hook) - (cons org-invoice-current-invoice - (org-invoice-collapse-list - (org-map-entries 'org-invoice-heading-info t 'tree 'archive)))))) - -(defun org-dblock-write:invoice (params) - "Function called by OrgMode to write the invoice dblock. To -create an invoice dblock you can use the `org-invoice-report' -function. - -The following parameters can be given to the invoice block (for -information about dblock parameters, please see the Org manual): - -:scope Allows you to override the `org-invoice-default-level' - variable. The only supported values right now are ones - that look like :tree1, :tree2, etc. - -:prices Set to nil to turn off the price column. - -:headers Set to nil to turn off the group headers. - -:summary Set to nil to turn off the final summary line." - (let ((scope (plist-get params :scope)) - (org-invoice-table-params params) - (zone (move-marker (make-marker) (point))) - table) - (unless scope (setq scope 'default)) - (unless (plist-member params :price) (plist-put params :price t)) - (unless (plist-member params :summary) (plist-put params :summary t)) - (unless (plist-member params :headers) (plist-put params :headers t)) - (save-excursion - (cond - ((eq scope 'tree) (org-invoice-goto-tree "tree1")) - ((eq scope 'default) (org-invoice-goto-tree)) - ((symbolp scope) (org-invoice-goto-tree (symbol-name scope)))) - (setq table (org-invoice-collect-invoice-data)) - (goto-char zone) - (org-invoice-list-to-table (cdr table)) - (goto-char zone) - (org-table-align) - (move-marker zone nil)))) - -(defun org-invoice-in-report-p () - "Check to see if point is inside an invoice report." - (let ((pos (point)) start) - (save-excursion - (end-of-line 1) - (and (re-search-backward "^#\\+BEGIN:[ \t]+invoice" nil t) - (setq start (match-beginning 0)) - (re-search-forward "^#\\+END:.*" nil t) - (>= (match-end 0) pos) - start)))) - -(defun org-invoice-report (&optional jump) - "Create or update an invoice dblock report. If point is inside -an existing invoice report, the report is updated. If point -isn't inside an invoice report, a new report is created. - -When called with a prefix argument, move to the first invoice -report after point and update it. - -For information about various settings for the invoice report, -see the `org-dblock-write:invoice' function documentation. - -An invoice report is created by reading a heading tree and -collecting information from various properties. It is assumed -that all invoices start at a second level heading, but this can -be configured using the `org-invoice-default-level' variable. - -Here is an example, where all invoices fall under the first-level -heading Invoices: - -* Invoices -** Client Foo (Jan 01 - Jan 15) -*** [2008-01-01 Tue] Built New Server for Production -*** [2008-01-02 Wed] Meeting with Team to Design New System -** Client Bar (Jan 01 - Jan 15) -*** [2008-01-01 Tue] Searched for Widgets on Google -*** [2008-01-02 Wed] Billed You for Taking a Nap - -In this layout, invoices begin at level two, and invoice -items (tasks) are at level three. You'll notice that each level -three heading starts with an inactive timestamp. The timestamp -can actually go anywhere you want, either in the heading, or in -the text under the heading. But you must have a timestamp -somewhere so that the invoice report can group your items by -date. - -Properties are used to collect various bits of information for -the invoice. All properties can be set on the invoice item -headings, or anywhere in the tree. The invoice report will scan -up the tree looking for each of the properties. - -Properties used: - -CLOCKSUM: You can use the Org clock-in and clock-out commands to - create a CLOCKSUM property. Also see WORK. - -WORK: An alternative to the CLOCKSUM property. This property - should contain the amount of work that went into this - invoice item formatted as HH:MM (e.g. 01:30). - -RATE: Used to calculate the total price for an invoice item. - Should be the price per hour that you charge (e.g. 45.00). - It might make more sense to place this property higher in - the hierarchy than on the invoice item headings. - -Using this information, a report is generated that details the -items grouped by days. For each day you will be able to see the -total number of hours worked, the total price, and the items -worked on. - -You can place the invoice report anywhere in the tree you want. -I place mine under a third-level heading like so: - -* Invoices -** An Invoice Header -*** [2008-11-25 Tue] An Invoice Item -*** Invoice Report -#+BEGIN: invoice -#+END:" - (interactive "P") - (let ((report (org-invoice-in-report-p))) - (when (and (not report) jump) - (when (re-search-forward "^#\\+BEGIN:[ \t]+invoice" nil t) - (org-show-entry) - (beginning-of-line) - (setq report (point)))) - (if report (goto-char report) - (org-create-dblock (list :name "invoice"))) - (org-update-dblock))) - -(provide 'org-invoice) |