Subversion Repositories OpenARM Single-board Computer

Rev

Rev 335 | Rev 417 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
280 agaran 1
#!/usr/bin/perl -w
2
use strict;
293 agaran 3
# $Id: inventory.pl 337 2009-01-23 16:29:03Z agaran $
280 agaran 4
# Thu, 13 Nov 2008 21:06:23 +0100
5
# Maciej 'agaran' Pijanka <agaran@pld-linux.org>
6
# for OpenARM SBC Project
7
# license: gpl v3
8
 
293 agaran 9
 
280 agaran 10
use Getopt::Long qw//;
293 agaran 11
use File::Basename qw/basename/;
322 agaran 12
use IO::Dir;
13
use IO::File;
280 agaran 14
 
325 agaran 15
use lib File::Basename::dirname($0).'/lib';
326 agaran 16
use Text::Table;
325 agaran 17
 
18
 
313 agaran 19
my %Config;
280 agaran 20
 
313 agaran 21
# ==================================================
22
$Config{docdir} = '.';
23
$Config{bomdir} = '.';
24
$Config{verbose} = 1;
280 agaran 25
 
313 agaran 26
# 0 mean not show, -1 show all, positive value limits depth of shown
27
$Config{dbg_showdirs} = 0;
280 agaran 28
 
313 agaran 29
 
30
# modes
31
my $build_inventory = 0;
32
my $build_bom = 0;
33
my $show_conf = 0;
34
my $show_help = 0;
35
 
36
# ==================================================
37
 
38
my %Inv_By_PartNo;
39
my @Inv;
325 agaran 40
my %BomData;
332 agaran 41
my %Files;
313 agaran 42
 
293 agaran 43
sub err_printf($@) {
44
        my ($format, @args) = @_;
280 agaran 45
 
313 agaran 46
        printf STDERR "-E- ".$format."\n", @args;
47
        # exit? or fail-exit here
280 agaran 48
}
49
 
293 agaran 50
sub wrn_printf($@) {
51
        my ($format, @args) = @_;
328 agaran 52
        return if ($Config{verbose} <= 1) ;
293 agaran 53
        printf STDERR "-W- ".$format."\n", @args;
54
}
55
 
56
sub inf_printf($@) {
57
        my ($format, @args) = @_;
328 agaran 58
        return if ($Config{verbose} <= 2) ;
293 agaran 59
        printf STDERR "-I- ".$format."\n", @args;
60
}
61
 
313 agaran 62
sub Config_Show {
63
        printf "Config for %s\n----------------------------------------\n", basename($0);
64
        foreach my $name (sort keys %Config) {
65
                printf "%-20s %s\n", $name, $Config{$name};
66
        }
67
}
68
 
69
sub Help_Show {
70
        printf "Help for %s\n----------------------------------------\n", basename($0);
71
        unless (defined($_[1]) && length($_[1]) != 0) {
72
                print "Basic help\n\t--showrc|showconf shows current configuration\n".
73
                        "\t--docdir|-d <dir> tells script where information.txt files should be searched\n".
74
                        "\t--define <something>=<somethingelseornot> defines some configration value\n".
319 agaran 75
                        "\t--verbose|-v [level] sets verbosity level\nOrder of options DOES matter\n".
330 agaran 76
                        "\t--bomdir|-b <dir> tells script where boms should be searched\n".
331 agaran 77
                        "\t--outfile|-o <file> tells where script shall save output data\n".
337 agaran 78
                        "\t--force|-f forces script to save data even if file exist already\n".
79
                        "\t-l <num> repeat title for output tables every <num> rows\n";
319 agaran 80
 
81
                print "\t\e[0;31mThis Help Is created especially for \e[0;33mJelle\e[0;29m\n".
82
                        "\tThis script search all directories below specified ones to find interesting files\n";
313 agaran 83
                return;
84
        }
85
        if ($_[1] =~ /^foo$/) {
86
                print "Noo, there is no foo's here\n";
87
        } else {
88
                printf "Sorry, help for `%s' don't exist (eventually) yet\n", $_[1];
89
        }
90
        exit;
91
}
92
 
93
sub fix_dir ($) {
94
        my $dir = shift @_;
95
 
96
        $dir =~ s/\/$//;
97
 
98
        if (! -d $dir) {
99
                err_printf("Sorry `%s' is not valid directory, exiting", $dir);
100
        }
101
 
102
        return $dir;
103
}
104
 
105
sub shortdir ($) {
106
        my $path = shift @_;
107
 
108
        return substr($path, 2) if ($path =~ /^\.\//) ;
109
        return $path;
110
}
111
 
112
 
113
sub trim($) {
114
        my ($value) = @_;
115
 
116
        $value =~ s/^ +//;
117
        $value =~ s/ +$//;
118
        return $value;
119
}
120
 
121
sub etrim($) {
122
        my ($value) = @_;
123
 
124
        $value =~ s/^[  ]+//;
125
        $value =~ s/[   ]+$//;
126
        return $value;
127
}
128
 
330 agaran 129
sub strbreak($$) {
325 agaran 130
        my ($str,$lim) = @_;
334 agaran 131
        my @p = split /\ /,$str;
330 agaran 132
        $str = '';
133
        my $l = 0;
134
        while (@p) {
135
                my $e = shift @p;
136
                if ($l + length ($e) +1 > $lim) {
137
                        $str .= "\n".$e;
138
                        $l = length $e;
139
                } else {
140
                        $str .= " ".$e;
141
                        $l += length($e) + 1;
142
                }
143
        }
325 agaran 144
        return $str;
145
}
146
 
313 agaran 147
# this subroutine is used as callback function
148
# executed by file_lookup
280 agaran 149
sub parse_ifile($) {
293 agaran 150
        my ($filepath) = @_;
280 agaran 151
 
318 agaran 152
 
293 agaran 153
        open(IN, $filepath) or return 1;
280 agaran 154
 
293 agaran 155
        my %data;
280 agaran 156
 
293 agaran 157
        while (not eof IN) {
158
                my $line = <IN>;
280 agaran 159
 
293 agaran 160
                chomp $line;
280 agaran 161
 
293 agaran 162
                next if ($line =~ /^[   ]*$/);
163
                next if ($line =~ /^;/);
164
 
165
                last if ($line =~ /^--/);
166
 
167
                if ($line =~ /^([A-Za-z ]+):(.*)$/) {
313 agaran 168
                        my ($name,$value) = (lc etrim($1),etrim($2));
293 agaran 169
 
170
                        if ($name =~ /^price$/) {
171
                                $value =~ s/[^0-9\.\,]//g;
172
                                if ($value =~ s/^([0-9]+)[,.]([0-9]+)$/$1.$2/) {
173
                                        # printf STDERR "Price %.3f\n", $value;
174
                                        if (!defined($data{price})) {
175
                                                $data{price} = $value;
176
                                        } else {
313 agaran 177
                                                wrn_printf("Duplicated price field in file %s", shortdir($filepath));
293 agaran 178
                                        }
179
                                } else {
313 agaran 180
                                        err_printf("Bad price field in file %s", shortdir($filepath));
293 agaran 181
                                }
182
                        } elsif ($name =~ /^manufacturer$/i) {
183
                                # printf STDERR "Manufacturer %s\n", $value;
184
                                if (!defined($data{manufacturer})) {
185
                                        $data{manufacturer} = $value;
186
                                } else {
313 agaran 187
                                        wrn_printf("Duplicated manufacturer field in file %s", shortdir($filepath));
293 agaran 188
                                }
189
                        } elsif ($name =~ /^manufacturer part no$/ ) {
190
                                # printf STDERR "ManPartNo %s\n", $value;
191
                                if (!defined($data{manufact_partno})) {
313 agaran 192
                                        $data{manufact_partno} = trim($value);
293 agaran 193
                                } else {
194
                                        wrn_printf("Duplicated manufacturer part no field in file %s",
313 agaran 195
                                                shortdir($filepath));
293 agaran 196
                                }
197
                        } elsif ($name =~ /^description$/i) {
313 agaran 198
                                if (!defined($data{desc})) {
199
                                        $data{desc} = $value;
200
                                } else {
201
                                        wrn_printf("Duplicated description no field in file %s",
202
                                                shortdir($filepath));
203
                                }
293 agaran 204
                        } elsif ($name =~ /^datasheet$/i) {
205
                                $data{datasheet} = [] unless defined $data{datasheet};
206
                                push @{$data{datasheet}}, $value;
207
                                # printf STDERR "Datasheet %s\n", $value;
208
                        } elsif ($name =~ /^supplier$/i) {
209
                                # printf STDERR "Supplier %s\n", $value;
210
                                if (!defined($data{supplier})) {
211
                                        $data{supplier} = $value;
212
                                } else {
213
                                        wrn_printf("Duplicated supplier field in file %s",
313 agaran 214
                                                shortdir($filepath));
293 agaran 215
                                }
216
                        } elsif ($name =~ /^order code$/) {
217
                                # printf STDERR "Order Code %s\n", $value;
218
                                if (!defined($data{ordercode})) {
219
                                        $data{ordercode} = $value;
220
                                } else {
221
                                        wrn_printf("Duplicated order code field in file %s",
313 agaran 222
                                                shortdir($filepath));
293 agaran 223
                                }
224
                                #push @DATA, { $name => $value };
225
                        } elsif ($name =~ /^url .*$/) {
226
                                # printf STDERR "URL %s\n", $value;
227
                        } elsif ($name =~ /^catalog(ue|) page$/) {
228
                                # printf STDERR "Catalogue Page %s\n", $value;
229
                        } else {
230
                                err_printf("Unhandled field %s in file %s", $name,
313 agaran 231
                                        shortdir($filepath));
293 agaran 232
                        }
233
 
234
                } else {
328 agaran 235
                        wrn_printf("Unparseable line `%s', forgot ; to set it as comment in file %s", $line,
313 agaran 236
                                shortdir($filepath));
293 agaran 237
                }
238
        }
239
        close(IN);
240
 
241
        if (scalar keys %data == 0) {
242
                inf_printf("Skipping file %s because contain no data for me",
313 agaran 243
                        shortdir($filepath));
293 agaran 244
                return;
245
        }
246
 
247
        unless (defined ($data{price}) && $data{price} != 0) {
248
                wrn_printf("Missing Price in file %s",
313 agaran 249
                        shortdir($filepath));
293 agaran 250
        }
251
 
252
        unless (defined($data{manufact_partno})) {
253
                inf_printf("Missing Manufacturer Part No in file %s",
313 agaran 254
                        shortdir($filepath));
293 agaran 255
        }
256
 
257
        unless (defined($data{ordercode})) {
258
                wrn_printf("Missing Order Code in file %s",
313 agaran 259
                        shortdir($filepath));
293 agaran 260
        }
261
 
313 agaran 262
 
293 agaran 263
        use Data::Dumper qw/Dumper/;
313 agaran 264
 
265
        my $id = scalar @Inv;
266
 
267
        $Inv[$id] = {};
268
 
269
        $Inv[$id]{Datasheet} = delete $data{'datasheet'} if defined $data{'datasheet'};
334 agaran 270
        $Inv[$id]{Manufacturer} = etrim(trim(delete $data{'manufacturer'})) if defined $data{'manufacturer'};
271
        $Inv[$id]{Description} = etrim(trim(delete $data{'desc'})) if defined $data{'desc'};
313 agaran 272
        $Inv[$id]{Price} = delete $data{'price'} if defined $data{'price'};
334 agaran 273
        $Inv[$id]{Ordercode} = etrim(trim(delete $data{'ordercode'})) if defined $data{'ordercode'};
274
        $Inv[$id]{Manufacturer_Partno} = etrim(trim(delete $data{'manufact_partno'})) if defined $data{'manufact_partno'};
313 agaran 275
        $Inv[$id]{Supplier} = delete $data{'supplier'} if defined $data{'supplier'};
276
 
277
        unless (defined ($Inv_By_PartNo{$Inv[$id]{Manufacturer_Partno}})) {
278
                $Inv_By_PartNo{$Inv[$id]{Manufacturer_Partno}} = $id;
279
        } else {
280
                wrn_printf("PartNumber %s happened more than once, using first occurence (id:%d)",
281
                        $Inv[$id]{Manufacturer_Partno}, $id);
282
        }
325 agaran 283
 
313 agaran 284
        #inf_printf("Part %s defined in file %s", $Inv[$id]{Manufacturer_Partno}, shortdir($filepath));
293 agaran 285
 
313 agaran 286
        wrn_printf("Unhandled data from parsing: %s", Dumper(\%data)) if (scalar keys %data > 0);
280 agaran 287
}
288
 
289
 
313 agaran 290
sub parse_bom ($) {
291
        my ($filepath) = @_;
280 agaran 292
 
313 agaran 293
        open(IN, $filepath) or return 1;
332 agaran 294
        my $fkey = substr(basename($filepath),0,length(basename($filepath))-4);
313 agaran 295
 
296
        #wrn_printf("GotARg: %s", shortdir($filepath));
297
 
298
        my @Fields;
299
 
300
        my %data;
301
        my $v = '';
302
        while (not eof IN) {
303
                my $line = <IN>;
304
 
305
                chomp $line;
306
 
307
                if ($line =~ /^\.START$/) {
308
                        $v = 'boms';
309
                        next;
310
                }
311
 
312
                if ($line =~ /^\.END$/) {
313
                        $v = '';
314
                        next;
315
                }
316
 
317
                if ($v eq 'boms') {
318
                        @Fields = split(/\t/, substr($line,2));
319
                        $v = 'bom';
320
                        # some funny way to generate field-map
321
                        # that if someone reorder bom file columns we are still on place
322
                        next;
323
                }
324
 
325
                if ($v eq 'bom') {
326
                        my ($refdes, $device, $value, $footprint, $quantity) = split (/\t/, $line);
327
 
328
                        $device = trim($device);
329
 
330
#                       wrn_printf("Device: %s (value: %s) at refdes %s, %d pcs", $device, $value, $refdes, $quantity);
331
 
332
                        if (!defined $Inv_By_PartNo{$device}) {
333
                                wrn_printf("Device %s not found in inventory in file %s", $device, shortdir($filepath));
334
                                next;
335
                        }
336
                        my $id = $Inv_By_PartNo{$device};
337
                        next if ($Inv[$id]{Manufacturer} =~ /none/i); # skip parts whose manufacturer is none
338
                        #inf_printf("Found in Inventory at %d %s", $id, $Inv[$id]{Manufacturer_Partno});
334 agaran 339
                        push @{$data{$id}{RefDes}}, etrim(trim($refdes));
330 agaran 340
                        if (!defined $data{$id}{Footprint}) {
341
                                $data{$id}{Footprint} = $footprint;
342
                        } else {
343
                                if ($data{$id}{Footprint} ne $footprint) {
344
                                        err_printf("Different footprints for same device in within single bom file, script ".
345
                                                "cannot work around this, will use first one, but expect that output file ".
346
                                                "might have errors.");
347
                                }
348
                        }
313 agaran 349
                }
350
        }
351
        close(IN);
352
 
353
        if (scalar keys %data == 0) {
354
                inf_printf("Skipping file %s because contain no data for me",
355
                        shortdir($filepath));
356
                return;
357
        }
358
 
359
        foreach my $id (keys %data) {
360
                my %tmp;
361
                map { $tmp{$_} = 1 } @{$data{$id}{RefDes}};
362
                @{$data{$id}{RefDes}} = keys %tmp;
363
                my $cnt = scalar @{$data{$id}{RefDes}};
364
                if (!defined $Inv[$id]{Price}) {
365
                        wrn_printf("%s has no price, setting to 0.0", $Inv[$id]{Manufacturer_Partno});
366
                        $Inv[$id]{Price} = 0;
367
                }
318 agaran 368
                push @{$BomData{$id}{RefDes}}, @{$data{$id}{RefDes}};
330 agaran 369
                if (!defined $BomData{$id}{Footprint}) {
370
                        $BomData{$id}{Footprint} = $data{$id}{Footprint};
371
                } else {
372
                        if ($data{$id}{Footprint} ne $data{$id}{Footprint}) {
373
                                err_printf("Different footprints for same device between sheets, script cannot ".
374
                                        "work around this, will use first one, but expect that output file might ".
375
                                        "have errors.");
376
                        }
377
                }
332 agaran 378
                push @{$BomData{$id}{Files}}, $fkey;
379
                push @{$Files{$fkey}{$id}{RefDes}}, @{$data{$id}{RefDes}};
318 agaran 380
 
313 agaran 381
#               printf "%-20s %.4f %s\n", $Inv[$id]{Manufacturer_Partno}, $cnt, $icost, join (', ', @{$data{$id}{RefDes}});
382
#               %BomData{ById}{$id}{RefDes}
383
        }
384
}
385
 
386
sub file_lookup ($$$$) ;
387
sub file_lookup ($$$$) {
388
        my ($dir, $depth, $regexp, $callback) = @_;
389
 
390
        err_printf("Sorry, callback must be CODE ref") unless (ref $callback eq 'CODE');
391
 
293 agaran 392
        if ( -d $dir) {
322 agaran 393
                my $d = IO::Dir->new($dir);
394
                return 1 if (!defined $d);
395
 
396
 
397
                while (defined(my $e = $d->read)) {
293 agaran 398
                        my $fe = $dir .'/'. $e;
399
                        if ( -f $fe) {
313 agaran 400
                                if ($fe =~ $regexp) {
401
                                        &$callback($fe);
293 agaran 402
                                }
403
                        } elsif (-d $fe) { # now its dir...
404
                                if ($e eq '.svn') { # if entry name is equal to svn
405
                                        next; # go to next entry in foreach loop
406
                                }
407
                                next if ($e eq '.' or $e eq '..'); # skip to next if dir entry is . or ..
281 jelle 408
 
313 agaran 409
                                if ($Config{dbg_showdirs} == -1 or $Config{dbg_showdirs} > $depth) {
410
                                        printf STDERR "Entering directory %s\n", shortdir($fe);
293 agaran 411
                                }
313 agaran 412
                                return 1 if (file_lookup($fe, $depth+1, $regexp, $callback) == 1);
293 agaran 413
                        } else {
313 agaran 414
                                # symlink or other mysterius beast
293 agaran 415
                        }
416
                }
417
        }
313 agaran 418
        return 0;
280 agaran 419
}
420
 
293 agaran 421
Getopt::Long::Configure("bundling");
280 agaran 422
 
319 agaran 423
if (scalar @ARGV == 0) {
424
        Help_Show();
425
        exit;
426
}
427
 
313 agaran 428
my $result = Getopt::Long::GetOptions (
429
        "showrc|showconf" => sub { $show_conf = 1 },
430
        "docdir|d=s" => sub { $Config{docdir} = $_[1]; },
431
        # not sure if bomdir or SCH dir
432
        "bomdir|b=s" => sub { $Config{$_[0]} = $_[1]; },  # $_[0] contain basename of option, so in few cases could be (ab)used
433
        "define|D=s" => sub { my ($p,$q) = split(/=/,$_[1],2); $Config{$p} = $q; },
434
        "verbose|v:+" => sub { $Config{$_[0]} = ($_[1]>1?0:$Config{$_[0]}) + $_[1]; },
330 agaran 435
        "help|h|?:s" => sub { $show_help = 1; },
436
        "outfile|o=s" => sub { $Config{$_[0]} = $_[1]; },
437
        "force|f" => sub { $Config{$_[0]} = 1 },
337 agaran 438
        "lines|l=i" => sub { $Config{$_[0]} = abs(int($_[1]));},
313 agaran 439
 
440
        # options 
293 agaran 441
);
442
if (!$result) {
443
        printf "Usage: %s [-d directory] [-v]\n",basename($0);
444
        exit;
445
}
313 agaran 446
 
447
# ==================================================
448
# processing of options/config values, checking ranges etc
449
# 
450
 
451
$Config{docdir} = fix_dir ($Config{docdir});
452
$Config{bomdir} = fix_dir ($Config{bomdir});
453
 
454
if ( $show_help == 1) {
455
        Help_Show();
456
        exit;
293 agaran 457
}
458
 
313 agaran 459
if ( $show_conf == 1) {
460
        Config_Show();
461
        exit;
462
}
293 agaran 463
 
313 agaran 464
# make Inventory
328 agaran 465
printf STDERR "Indexing information.txt (under %s)\n",shortdir($Config{docdir});
313 agaran 466
file_lookup($Config{docdir}, 0, qr/\/information.txt$/, \&parse_ifile);
328 agaran 467
printf STDERR "\tFinished, %d entries loaded\n", scalar(@Inv)+1;
313 agaran 468
 
469
# process BOM files
328 agaran 470
printf STDERR "Loading bom data from %s\n", shortdir($Config{bomdir});
313 agaran 471
file_lookup($Config{bomdir}, 0, qr/\.bom$/, \&parse_bom);
328 agaran 472
printf STDERR "\tLoaded, now processing\n";
313 agaran 473
 
330 agaran 474
my ($bn,$pn) = (1,1);
318 agaran 475
my $cost = 0.0;
476
 
330 agaran 477
my $out;
478
if (!defined $Config{outfile}) {
479
        $Config{outfile} = './output.txt';
480
        wrn_printf("Output file not specified, saving out in ".$Config{outfile});
481
}
318 agaran 482
 
330 agaran 483
if ( -e $Config{outfile}) {
484
        unless (defined $Config{force} && $Config{force} == 1) {
485
                inf_printf("Unlinking output.txt before owrewriting");
486
                unlink($Config{outfile});
487
        } else {
488
                wrn_printf("Output file already exist, add --force if i shall overwrite it");
489
                exit;
490
        }
491
}
318 agaran 492
 
330 agaran 493
$out = new IO::File $Config{outfile}, 'w';
318 agaran 494
 
325 agaran 495
my $bomtable = Text::Table->new(
327 agaran 496
        { title => '| ', is_sep => 1 },
329 jelle 497
        { title => 'id', align => 'right', align_title => 'left' },
327 agaran 498
        { title => ' | ', is_sep => 1 },
329 jelle 499
        { title => 'description', align => 'left', align_title => 'left' },
327 agaran 500
        { title => ' | ', is_sep => 1 },
329 jelle 501
        { title => 'manufacturer partid', align => 'left', align_title => 'left' },
327 agaran 502
        { title => ' | ', is_sep => 1 },
329 jelle 503
        { title => 'manufacturer', align => 'left', align_title => 'left' },
327 agaran 504
        { title => ' | ', is_sep => 1 },
329 jelle 505
        { title => 'order code', align => 'left', align_title => 'left' },
327 agaran 506
        { title => ' | ', is_sep => 1 },
329 jelle 507
        { title => 'quantity', align => 'right', align_title => 'left' },
327 agaran 508
        { title => ' | ', is_sep => 1 },
329 jelle 509
        { title => "price", align => 'right', align_title => 'left' },
327 agaran 510
        { title => ' | ', is_sep => 1 },
329 jelle 511
        { title => "cost", align => 'right', align_title => 'left' },
327 agaran 512
        { title => ' |', is_sep => 1 },
325 agaran 513
);
330 agaran 514
 
515
my $parttable = Text::Table->new(
516
        { title => '| ', is_sep => 1 },
517
        { title => 'id', align => 'right', align_title => 'center' },
518
        { title => ' | ', is_sep => 1 },
519
        { title => 'description', align => 'left', align_title => 'center' },
520
        { title => ' | ', is_sep => 1 },
335 agaran 521
        { title => 'manufacturer partid', align => 'left', align_title => 'center' },
330 agaran 522
        { title => ' | ', is_sep => 1 },
523
        { title => 'footprint', align => 'left', align_title => 'center' },
524
        { title => ' | ', is_sep => 1 },
525
        { title => 'refdes', align => 'left', align_title => 'center' },
526
        { title => ' | ', is_sep => 1 },
527
        { title => 'sheet', align => 'left', align_title => 'center' },
528
        { title => ' |', is_sep => 1 },
529
);
325 agaran 530
 
531
foreach my $id ( sort {my $p = $Inv[$a]{Manufacturer} cmp $Inv[$b]{Manufacturer}; if ($p == 0) {
532
#               return $Inv[$a]{Manufacturer_Partno} cmp $Inv[$b]{Manufacturer_Partno}}; return $p; }  keys %BomData) {
533
                return $Inv[$a]{Description} cmp $Inv[$b]{Description}}; return $p; }  keys %BomData) {
318 agaran 534
        my %tmp;
535
        map { $tmp{$_} = 1 } @{$BomData{$id}{RefDes}};
536
        @{$BomData{$id}{RefDes}} = keys %tmp;
325 agaran 537
        my $quant = scalar @{$BomData{$id}{RefDes}};
318 agaran 538
        if (!defined $Inv[$id]{Price}) {
539
                wrn_printf("%s has no price, setting to 0.0", $Inv[$id]{Manufacturer_Partno});
540
                $Inv[$id]{Price} = 0;
541
        }
325 agaran 542
        my $icost = $quant * $Inv[$id]{Price};
318 agaran 543
 
330 agaran 544
#       printf PARTMAP "%-35s|%s\n", shortstring($Inv[$id]{Description},35), join (', ', sort @{$BomData{$id}{RefDes}});
318 agaran 545
        $cost += $icost;
546
#       %BomData{ById}{$id}{RefDes}
327 agaran 547
#       $bomtable->add(' '.$n.' ', $Inv[$id]{Description}.' ', $Inv[$id]{Manufacturer_Partno}.' ', $Inv[$id]{Manufacturer}.' ',
548
#               $Inv[$id]{Ordercode}.' ', ' '.$quant.' ', sprintf("%.3f ",$Inv[$id]{Price}), sprintf("%.3f ",$icost));
330 agaran 549
        $bomtable->add($bn++, $Inv[$id]{Description}, $Inv[$id]{Manufacturer_Partno}, $Inv[$id]{Manufacturer},
327 agaran 550
                $Inv[$id]{Ordercode},$quant, sprintf("%.3f",$Inv[$id]{Price}), sprintf("%.3f",$icost));
330 agaran 551
 
332 agaran 552
#       $parttable->add($pn++, $Inv[$id]{Description}, $Inv[$id]{Manufacturer_Partno}, $BomData{$id}{Footprint}, 
553
#               strbreak(join (', ', sort @{$BomData{$id}{RefDes}}),43), join("\n",@{$BomData{$id}{Files}}));
318 agaran 554
}
555
 
332 agaran 556
 
325 agaran 557
printf $out "file generated at %s\n\n", scalar localtime(time());
558
 
559
print $out $bomtable->rule('-','+');
560
print $out $bomtable->title();
561
print $out $bomtable->rule('-','+');
337 agaran 562
unless (defined $Config{'lines'}) {
563
        print $out $bomtable->body();
564
} else {
565
        my @p = split(/\n/,$bomtable->body());
566
        while (@p) {
567
                my @sub = splice @p,0,$Config{'lines'};
568
                print $out join("\n",@sub)."\n";
569
                if (scalar @p > 0) {
570
                        print $out $bomtable->rule('-','+');
571
                        print $out $bomtable->title();
572
                        print $out $bomtable->rule('-','+');
573
                }
574
        }
575
}
325 agaran 576
print $out $bomtable->rule('-','+');
577
 
330 agaran 578
printf $out "\nTotal cost: %.3f\n\n\n", $cost;
325 agaran 579
 
332 agaran 580
 
333 agaran 581
$pn = 1;
332 agaran 582
foreach my $fkey (sort keys %Files) {
583
        my $rowblock = 0;
584
        foreach my $id ( sort {my $p = $Inv[$a]{Manufacturer} cmp $Inv[$b]{Manufacturer}; if ($p == 0) {
585
                return $Inv[$a]{Description} cmp $Inv[$b]{Description}}; return $p; }  keys %{$Files{$fkey}}) {
586
 
334 agaran 587
                my @p = split(/\n/, strbreak(join (', ', sort @{$Files{$fkey}{$id}{RefDes}}),43));
588
                while (@p) {
589
                        $parttable->add($pn, $Inv[$id]{Description}, $Inv[$id]{Manufacturer_Partno}, $BomData{$id}{Footprint},
590
                                etrim(trim(shift @p)), $fkey);
591
                }
332 agaran 592
 
334 agaran 593
                $pn++;
332 agaran 594
        }
595
        $parttable->add('--','=========','==========','==========','==========','==========');
596
}
597
 
330 agaran 598
print $out $parttable->rule('-','+');
599
print $out $parttable->title();
600
print $out $parttable->rule('-','+');
337 agaran 601
unless (defined $Config{'lines'}) {
602
        print $out $parttable->body();
603
} else {
604
        my @p = split(/\n/,$parttable->body());
605
        while (@p) {
606
                my @sub = splice @p,0,$Config{'lines'};
607
                print $out join("\n",@sub)."\n";
608
                if (scalar @p > 0) {
609
                        print $out $parttable->rule('-','+');
610
                        print $out $parttable->title();
611
                        print $out $parttable->rule('-','+');
612
                }
613
        }
614
}
330 agaran 615
print $out $parttable->rule('-','+');
325 agaran 616
 
330 agaran 617
 
618
#close PARTMAP;
619
 
620
printf STDERR "\tFinished, output saved in %s\n", $Config{outfile};